From: Jason Merrill <jason@redhat.com>
To: gcc-patches List <gcc-patches@gcc.gnu.org>
Cc: David Malcolm <dmalcolm@redhat.com>
Subject: C++ PATCH for c++/79228, complex literal suffixes
Date: Fri, 01 Dec 2017 20:16:00 -0000 [thread overview]
Message-ID: <CADzB+2nOhF+ZEbid8AMXbxjHP8=Rkfp59hnREOFrKAv=NeQCcw@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 586 bytes --]
79228 points out that C++14 defines complex literal suffixes that
conflict with the GNU suffixes. In this patch I take the approach
that in C++14 and up, if <complex> has been included we assume that
the user wants the C++14 suffixes and give a hard error if they aren't
found; otherwise we assume that the user wants the GNU suffixes and
give a pedwarn if -Wpedantic.
While looking at this, I noticed that David's #include suggestion code
wasn't suggesting <complex> for references to std::complex, so the
second patch addresses that.
Tested x86_64-pc-linux-gnu, applying to trunk.
[-- Attachment #2: 79228.diff --]
[-- Type: text/plain, Size: 9944 bytes --]
commit e39b7d506d236ce7ef9f64d1bcf0b384bb2d8038
Author: Jason Merrill <jason@redhat.com>
Date: Fri Dec 1 07:45:03 2017 -0500
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.
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 <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
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 <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
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 <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
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 <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
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 <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>{};
+}
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)
[-- Attachment #3: complex-hint.diff --]
[-- Type: text/plain, Size: 2879 bytes --]
commit 59576ea299c27f6b3f29eb5e6171949a72720dbe
Author: Jason Merrill <jason@redhat.com>
Date: Fri Dec 1 13:22:40 2017 -0500
Give #include hints for <complex>.
* name-lookup.c (get_std_name_hint): Add <complex>.
* parser.c (cp_parser_diagnose_invalid_type_name): Call
suggest_alternative_in_explicit_scope.
(cp_parser_namespace_name): Likewise.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 9f65c4d7992..62ea564cedd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -5414,6 +5414,9 @@ get_std_name_hint (const char *name)
static const std_name_hint hints[] = {
/* <array>. */
{"array", "<array>"}, // C++11
+ /* <complex>. */
+ {"complex", "<complex>"},
+ {"complex_literals", "<complex>"},
/* <deque>. */
{"deque", "<deque>"},
/* <forward_list>. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 6e4c24362c6..891f742eb21 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3365,6 +3365,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
id, parser->scope);
if (DECL_P (decl))
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
+ else if (decl == error_mark_node)
+ suggest_alternative_in_explicit_scope (location, id,
+ parser->scope);
}
else if (CLASS_TYPE_P (parser->scope)
&& constructor_name_p (id, parser->scope))
@@ -18408,7 +18411,13 @@ cp_parser_namespace_name (cp_parser* parser)
|| TREE_CODE (namespace_decl) != NAMESPACE_DECL)
{
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
- error_at (token->location, "%qD is not a namespace-name", identifier);
+ {
+ error_at (token->location, "%qD is not a namespace-name", identifier);
+ if (namespace_decl == error_mark_node
+ && parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
+ suggest_alternative_in_explicit_scope (token->location, identifier,
+ parser->scope);
+ }
cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node;
}
diff --git a/gcc/testsuite/g++.dg/lookup/missing-std-include-4.C b/gcc/testsuite/g++.dg/lookup/missing-std-include-4.C
new file mode 100644
index 00000000000..abf4e96bd3e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/missing-std-include-4.C
@@ -0,0 +1,2 @@
+std::complex<int> c; // { dg-error "" }
+// { dg-message "#include <complex>" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/lookup/missing-std-include-5.C b/gcc/testsuite/g++.dg/lookup/missing-std-include-5.C
new file mode 100644
index 00000000000..fe880a6263b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/missing-std-include-5.C
@@ -0,0 +1,2 @@
+using namespace std::complex_literals; // { dg-error "" }
+// { dg-message "#include <complex>" "" { target *-*-* } .-1 }
next reply other threads:[~2017-12-01 20:16 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-01 20:16 Jason Merrill [this message]
2017-12-05 12:33 ` Jakub Jelinek
2017-12-05 14:24 ` Jason Merrill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CADzB+2nOhF+ZEbid8AMXbxjHP8=Rkfp59hnREOFrKAv=NeQCcw@mail.gmail.com' \
--to=jason@redhat.com \
--cc=dmalcolm@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).