PR c++/79228 - extensions hide C++14 complex literal operators
authorJason Merrill <jason@redhat.com>
Fri, 1 Dec 2017 20:19:07 +0000 (15:19 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 1 Dec 2017 20:19:07 +0000 (15:19 -0500)
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
gcc/cp/parser.c
gcc/testsuite/g++.dg/cpp0x/gnu_fext-numeric-literals.C
gcc/testsuite/g++.dg/cpp0x/std_fext-numeric-literals.C
gcc/testsuite/g++.dg/cpp1y/complex_literals1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/complex_literals1a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/complex_literals2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C [new file with mode: 0644]
libcpp/ChangeLog
libcpp/expr.c

index 71f6f3a3ca3a0214e9b52c42768f9085e716e63c..89680a20d6bf9fb8753da518b274488b80db367c 100644 (file)
@@ -1,3 +1,9 @@
+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.
index b469d1c176062202855d91d2225fe9540dde180c..6e4c24362c6e6f335605c62e7c50ede5f1eb7a7a 100644 (file)
@@ -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 <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
index 6a8398b896a1df427b535132ef79905d6a7ea765..ac2db287f3a24b8ab13d15b2c1aef6078118122a 100644 (file)
@@ -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
index 7caaa7cee8d486f96723eae22bb34b4594ac1f5f..ff1e7b6d966f7809c4ebdd9186da99fa22fe00ab 100644 (file)
@@ -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 (file)
index 0000000..5ae2370
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/79228
+// { dg-do compile { target c++14 } }
+
+#include <complex>
+
+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 (file)
index 0000000..9b61f3a
--- /dev/null
@@ -0,0 +1,11 @@
+// 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 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals2.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals2.C
new file mode 100644 (file)
index 0000000..6dd9947
--- /dev/null
@@ -0,0 +1,25 @@
+// 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 }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C b/gcc/testsuite/g++.dg/cpp1y/complex_literals2a.C
new file mode 100644 (file)
index 0000000..9ee9f3f
--- /dev/null
@@ -0,0 +1,14 @@
+// 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>{};
+}
index 2250b7716d2a54ff3d30a78a35505479105cfd91..ec0492185f2cb6a2c734aaa016a0652dad8bc22e 100644 (file)
@@ -1,3 +1,9 @@
+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
index 04675d8faee2a9d7d1ead03e7cb36f38d7bd2779..fe9f6b0188c3b0a9019a440c83a688853fabfa54 100644 (file)
@@ -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)