+2017-12-01 Jason Merrill <jason@redhat.com>
+
+ 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 <jakub@redhat.com>
* parser.c (cp_parser_new): Don't clear cilk_simd_fn_info.
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 <complex> 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 <complex>, 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 %<using namespace std::complex_literals%> "
+ "(from <complex>) to enable the C++14 user-defined literal "
+ "suffixes");
+ if (ext)
+ inform (token->location, "or use %<j%> instead of %<i%> 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
// 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
// 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
// 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
// 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
--- /dev/null
+// PR c++/79228
+// { dg-do compile { target c++14 } }
+
+#include <complex>
+
+int main()
+{
+ using namespace std::complex_literals;
+ auto a = std::abs(0.0i);
+}
--- /dev/null
+// PR c++/79228
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+#include <complex>
+
+int main()
+{
+ auto a = std::abs(0.0i); // { dg-error "literal operator" }
+ // { dg-message "complex_literals" "" { target *-*-* } .-1 }
+}
--- /dev/null
+// PR c++/79228
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wpedantic" }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> { };
+
+int main()
+{
+ same<decltype(0i),__complex int>{}; // { dg-warning "literal operator" }
+ // { dg-message "complex_literals" "" { target *-*-* } .-1 }
+ // { dg-message "built-in" "" { target *-*-* } .-2 }
+
+ same<decltype(0.0i),__complex double>{}; // { dg-warning "literal operator" }
+ // { dg-message "complex_literals" "" { target *-*-* } .-1 }
+ // { dg-message "built-in" "" { target *-*-* } .-2 }
+
+ same<decltype(0.0if),__complex float>{}; // { dg-warning "literal operator" }
+ // { dg-message "complex_literals" "" { target *-*-* } .-1 }
+ // { dg-message "built-in" "" { target *-*-* } .-2 }
+
+ same<decltype(0.0il),__complex long double>{}; // { dg-warning "literal operator" }
+ // { dg-message "complex_literals" "" { target *-*-* } .-1 }
+ // { dg-message "built-in" "" { target *-*-* } .-2 }
+}
--- /dev/null
+// PR c++/79228
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+template <class,class> struct same;
+template <class T> struct same<T,T> { };
+
+int main()
+{
+ same<decltype(0i),__complex int>{};
+ same<decltype(0.0i),__complex double>{};
+ same<decltype(0.0if),__complex float>{};
+ same<decltype(0.0il),__complex long double>{};
+}
+2017-12-01 Jason Merrill <jason@redhat.com>
+
+ 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 <dmalcolm@redhat.com>
PR c/82050
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;
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;
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;
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)