From f2b8b8adbae9968ac30742498a21a92ac70523ff Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 1 Dec 2017 15:19:07 -0500 Subject: [PATCH] PR c++/79228 - extensions hide C++14 complex literal operators libcpp/ * expr.c (interpret_float_suffix): Ignore 'i' in C++14 and up. (interpret_int_suffix): Likewise. gcc/cp/ * parser.c (cp_parser_userdef_numeric_literal): Be helpful about 'i' in C++14 and up. From-SVN: r255335 --- gcc/cp/ChangeLog | 6 ++ gcc/cp/parser.c | 72 +++++++++++++++++-- .../g++.dg/cpp0x/gnu_fext-numeric-literals.C | 4 +- .../g++.dg/cpp0x/std_fext-numeric-literals.C | 4 +- .../g++.dg/cpp1y/complex_literals1.C | 10 +++ .../g++.dg/cpp1y/complex_literals1a.C | 11 +++ .../g++.dg/cpp1y/complex_literals2.C | 25 +++++++ .../g++.dg/cpp1y/complex_literals2a.C | 14 ++++ libcpp/ChangeLog | 6 ++ libcpp/expr.c | 35 +++++++-- 10 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/complex_literals1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/complex_literals1a.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/complex_literals2.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 71f6f3a3ca3..89680a20d6b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2017-12-01 Jason Merrill + + PR c++/79228 - extensions hide C++14 complex literal operators + * parser.c (cp_parser_userdef_numeric_literal): Be helpful about + 'i' in C++14 and up. + 2017-12-01 Jakub Jelinek * parser.c (cp_parser_new): Don't clear cilk_simd_fn_info. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b469d1c1760..6e4c24362c6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4397,11 +4397,75 @@ cp_parser_userdef_numeric_literal (cp_parser *parser) release_tree_vector (args); - error ("unable to find numeric literal operator %qD", name); - if (!cpp_get_options (parse_in)->ext_numeric_literals) - inform (token->location, "use -std=gnu++11 or -fext-numeric-literals " + /* In C++14 the standard library defines complex number suffixes that + conflict with GNU extensions. Prefer them if is #included. */ + bool ext = cpp_get_options (parse_in)->ext_numeric_literals; + bool i14 = (cxx_dialect > cxx11 + && (id_equal (suffix_id, "i") + || id_equal (suffix_id, "if") + || id_equal (suffix_id, "il"))); + diagnostic_t kind = DK_ERROR; + int opt = 0; + + if (i14 && ext) + { + tree cxlit = lookup_qualified_name (std_node, + get_identifier ("complex_literals"), + 0, false, false); + if (cxlit == error_mark_node) + { + /* No , so pedwarn and use GNU semantics. */ + kind = DK_PEDWARN; + opt = OPT_Wpedantic; + } + } + + bool complained + = emit_diagnostic (kind, input_location, opt, + "unable to find numeric literal operator %qD", name); + + if (!complained) + /* Don't inform either. */; + else if (i14) + { + inform (token->location, "add % " + "(from ) to enable the C++14 user-defined literal " + "suffixes"); + if (ext) + inform (token->location, "or use % instead of % for the " + "GNU built-in suffix"); + } + else if (!ext) + inform (token->location, "use -fext-numeric-literals " "to enable more built-in suffixes"); - return error_mark_node; + + if (kind == DK_ERROR) + value = error_mark_node; + else + { + /* Use the built-in semantics. */ + tree type; + if (id_equal (suffix_id, "i")) + { + if (TREE_CODE (value) == INTEGER_CST) + type = integer_type_node; + else + type = double_type_node; + } + else if (id_equal (suffix_id, "if")) + type = float_type_node; + else /* if (id_equal (suffix_id, "il")) */ + type = long_double_type_node; + + value = build_complex (build_complex_type (type), + fold_convert (type, integer_zero_node), + fold_convert (type, value)); + } + + if (cp_parser_uncommitted_to_tentative_parse_p (parser)) + /* Avoid repeated diagnostics. */ + token->u.value = value; + return value; } /* Parse a user-defined string constant. Returns a call to a user-defined diff --git a/gcc/testsuite/g++.dg/cpp0x/gnu_fext-numeric-literals.C b/gcc/testsuite/g++.dg/cpp0x/gnu_fext-numeric-literals.C index 6a8398b896a..ac2db287f3a 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gnu_fext-numeric-literals.C +++ b/gcc/testsuite/g++.dg/cpp0x/gnu_fext-numeric-literals.C @@ -4,7 +4,7 @@ // Integer imaginary... constexpr unsigned long long -operator"" i(unsigned long long n) // { dg-warning "shadowed by implementation" } +operator"" i(unsigned long long n) // { dg-warning "shadowed by implementation" "" { target c++11_only } } { return 4 * n + 0; } constexpr unsigned long long @@ -22,7 +22,7 @@ operator"" J(unsigned long long n) // { dg-warning "shadowed by implementation" // Floating-point imaginary... constexpr long double -operator"" i(long double n) // { dg-warning "shadowed by implementation" } +operator"" i(long double n) // { dg-warning "shadowed by implementation" "" { target c++11_only } } { return 4.0L * n + 0.0L; } constexpr long double diff --git a/gcc/testsuite/g++.dg/cpp0x/std_fext-numeric-literals.C b/gcc/testsuite/g++.dg/cpp0x/std_fext-numeric-literals.C index 7caaa7cee8d..ff1e7b6d966 100644 --- a/gcc/testsuite/g++.dg/cpp0x/std_fext-numeric-literals.C +++ b/gcc/testsuite/g++.dg/cpp0x/std_fext-numeric-literals.C @@ -4,7 +4,7 @@ // Integer imaginary... constexpr unsigned long long -operator"" i(unsigned long long n) // { dg-warning "shadowed by implementation" } +operator"" i(unsigned long long n) // { dg-warning "shadowed by implementation" "" { target c++11_only } } { return 4 * n + 0; } constexpr unsigned long long @@ -22,7 +22,7 @@ operator"" J(unsigned long long n) // { dg-warning "shadowed by implementation" // Floating-point imaginary... constexpr long double -operator"" i(long double n) // { dg-warning "shadowed by implementation" } +operator"" i(long double n) // { dg-warning "shadowed by implementation" "" { target c++11_only } } { return 4.0L * n + 0.0L; } constexpr long double diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals1.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals1.C new file mode 100644 index 00000000000..5ae2370c3ff --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/complex_literals1.C @@ -0,0 +1,10 @@ +// PR c++/79228 +// { dg-do compile { target c++14 } } + +#include + +int main() +{ + using namespace std::complex_literals; + auto a = std::abs(0.0i); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals1a.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals1a.C new file mode 100644 index 00000000000..9b61f3aa534 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/complex_literals1a.C @@ -0,0 +1,11 @@ +// PR c++/79228 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +#include + +int main() +{ + auto a = std::abs(0.0i); // { dg-error "literal operator" } + // { dg-message "complex_literals" "" { target *-*-* } .-1 } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals2.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals2.C new file mode 100644 index 00000000000..6dd9947dab8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/complex_literals2.C @@ -0,0 +1,25 @@ +// PR c++/79228 +// { dg-do compile { target c++14 } } +// { dg-options "-Wpedantic" } + +template struct same; +template struct same { }; + +int main() +{ + same{}; // { dg-warning "literal operator" } + // { dg-message "complex_literals" "" { target *-*-* } .-1 } + // { dg-message "built-in" "" { target *-*-* } .-2 } + + same{}; // { dg-warning "literal operator" } + // { dg-message "complex_literals" "" { target *-*-* } .-1 } + // { dg-message "built-in" "" { target *-*-* } .-2 } + + same{}; // { dg-warning "literal operator" } + // { dg-message "complex_literals" "" { target *-*-* } .-1 } + // { dg-message "built-in" "" { target *-*-* } .-2 } + + same{}; // { dg-warning "literal operator" } + // { dg-message "complex_literals" "" { target *-*-* } .-1 } + // { dg-message "built-in" "" { target *-*-* } .-2 } +} diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C new file mode 100644 index 00000000000..9ee9f3fd24d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C @@ -0,0 +1,14 @@ +// PR c++/79228 +// { dg-do compile { target c++14 } } +// { dg-options "" } + +template struct same; +template struct same { }; + +int main() +{ + same{}; + same{}; + same{}; + same{}; +} diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 2250b7716d2..ec0492185f2 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,9 @@ +2017-12-01 Jason Merrill + + PR c++/79228 - extensions hide C++14 complex literal operators + * expr.c (interpret_float_suffix): Ignore 'i' in C++14 and up. + (interpret_int_suffix): Likewise. + 2017-11-28 David Malcolm PR c/82050 diff --git a/libcpp/expr.c b/libcpp/expr.c index 04675d8faee..fe9f6b0188c 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -90,6 +90,8 @@ static cpp_num parse_has_include (cpp_reader *, enum include_type); static unsigned int interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len) { + size_t orig_len = len; + const uchar *orig_s = s; size_t flags; size_t f, d, l, w, q, i, fn, fnx, fn_bits; @@ -269,8 +271,20 @@ interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len) if (fn && fn_bits == 96) return 0; - if (i && !CPP_OPTION (pfile, ext_numeric_literals)) - return 0; + if (i) + { + if (!CPP_OPTION (pfile, ext_numeric_literals)) + return 0; + + /* In C++14 and up these suffixes are in the standard library, so treat + them as user-defined literals. */ + if (CPP_OPTION (pfile, cplusplus) + && CPP_OPTION (pfile, lang) > CLK_CXX11 + && (!memcmp (orig_s, "i", orig_len) + || !memcmp (orig_s, "if", orig_len) + || !memcmp (orig_s, "il", orig_len))) + return 0; + } if ((w || q) && !CPP_OPTION (pfile, ext_numeric_literals)) return 0; @@ -299,6 +313,7 @@ cpp_interpret_float_suffix (cpp_reader *pfile, const char *s, size_t len) static unsigned int interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len) { + size_t orig_len = len; size_t u, l, i; u = l = i = 0; @@ -321,8 +336,20 @@ interpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len) if (l > 2 || u > 1 || i > 1) return 0; - if (i && !CPP_OPTION (pfile, ext_numeric_literals)) - return 0; + if (i) + { + if (!CPP_OPTION (pfile, ext_numeric_literals)) + return 0; + + /* In C++14 and up these suffixes are in the standard library, so treat + them as user-defined literals. */ + if (CPP_OPTION (pfile, cplusplus) + && CPP_OPTION (pfile, lang) > CLK_CXX11 + && (!memcmp (s, "i", orig_len) + || !memcmp (s, "if", orig_len) + || !memcmp (s, "il", orig_len))) + return 0; + } return ((i ? CPP_N_IMAGINARY : 0) | (u ? CPP_N_UNSIGNED : 0)