Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? I'm not certain OPT_Wc__20_extensions is the best thing for something from [diff.cpp17]; would you prefer something else?
-- >8 -- Since my r11-532 changes to implement DR2237, for this test: template<typename T> struct S { S<T>(); }; in C++20 we emit the ugly: q.C:3:8: error: expected unqualified-id before ')' token 3 | S<T>(); which doesn't explain what the problem is. This patch improves that diagnostic, reduces the error to a pedwarn, and adds a -Wc++20-compat diagnostic. We now say: q.C:3:7: warning: template-id not allowed for constructor [-Wc++20-extensions] 3 | S<T>(); This patch does *not* fix <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97202#c8> where the C++20 diagnostic is missing altogether. Something for the next stage1 I reckon. -Wc++20-compat triggered in libitm/; I sent a patch for that. DR 2237 PR c++/107126 PR c++/97202 gcc/cp/ChangeLog: * parser.cc (cp_parser_unqualified_id): Downgrade the DR2237 error to a pedwarn. Emit a -Wc++20-compat message. (cp_parser_constructor_declarator_p): Likewise. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2237.C: Adjust dg-error. * g++.dg/parse/constructor2.C: Likewise. * g++.dg/template/error34.C: Likewise. * g++.old-deja/g++.pt/ctor2.C: Likewise. * g++.dg/DRs/dr2237-2.C: New test. * g++.dg/DRs/dr2237-3.C: New test. * g++.dg/DRs/dr2237-4.C: New test. * g++.dg/diagnostic/cdtor-template1.C: New test. --- gcc/cp/parser.cc | 33 ++++++++++++++----- gcc/testsuite/g++.dg/DRs/dr2237-2.C | 9 +++++ gcc/testsuite/g++.dg/DRs/dr2237-3.C | 16 +++++++++ gcc/testsuite/g++.dg/DRs/dr2237-4.C | 11 +++++++ gcc/testsuite/g++.dg/DRs/dr2237.C | 2 +- .../g++.dg/diagnostic/cdtor-template1.C | 9 +++++ gcc/testsuite/g++.dg/parse/constructor2.C | 16 ++++----- gcc/testsuite/g++.dg/template/error34.C | 10 +++--- gcc/testsuite/g++.old-deja/g++.pt/ctor2.C | 2 +- 9 files changed, 85 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/g++.dg/DRs/dr2237-2.C create mode 100644 gcc/testsuite/g++.dg/DRs/dr2237-3.C create mode 100644 gcc/testsuite/g++.dg/DRs/dr2237-4.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/cdtor-template1.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 3748ccd49ff..4f7d4edbad9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -6717,12 +6717,17 @@ cp_parser_unqualified_id (cp_parser* parser, /* DR 2237 (C++20 only): A simple-template-id is no longer valid as the declarator-id of a constructor or destructor. */ - if (token->type == CPP_TEMPLATE_ID && declarator_p - && cxx_dialect >= cxx20) + if (token->type == CPP_TEMPLATE_ID && declarator_p) { - if (!cp_parser_simulate_error (parser)) - error_at (tilde_loc, "template-id not allowed for destructor"); - return error_mark_node; + if (cxx_dialect >= cxx20) + { + if (!cp_parser_simulate_error (parser)) + pedwarn (tilde_loc, OPT_Wc__20_extensions, + "template-id not allowed for destructor"); + return error_mark_node; + } + warning_at (tilde_loc, OPT_Wc__20_compat, + "template-id not allowed for destructor in C++20"); } /* If there was an explicit qualification (S::~T), first look @@ -32329,11 +32334,11 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, if (next_token->type != CPP_NAME && next_token->type != CPP_SCOPE && next_token->type != CPP_NESTED_NAME_SPECIFIER - /* DR 2237 (C++20 only): A simple-template-id is no longer valid as the - declarator-id of a constructor or destructor. */ - && (next_token->type != CPP_TEMPLATE_ID || cxx_dialect >= cxx20)) + && next_token->type != CPP_TEMPLATE_ID) return false; + const bool saw_template_id = (next_token->type == CPP_TEMPLATE_ID); + /* Parse tentatively; we are going to roll back all of the tokens consumed here. */ cp_parser_parse_tentatively (parser); @@ -32550,6 +32555,18 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags, /* We did not really want to consume any tokens. */ cp_parser_abort_tentative_parse (parser); + /* DR 2237 (C++20 only): A simple-template-id is no longer valid as the + declarator-id of a constructor or destructor. */ + if (constructor_p && saw_template_id) + { + if (cxx_dialect >= cxx20) + pedwarn (input_location, OPT_Wc__20_extensions, + "template-id not allowed for constructor"); + else + warning (OPT_Wc__20_compat, + "template-id not allowed for constructor in C++20"); + } + return constructor_p; } diff --git a/gcc/testsuite/g++.dg/DRs/dr2237-2.C b/gcc/testsuite/g++.dg/DRs/dr2237-2.C new file mode 100644 index 00000000000..1d99347229c --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2237-2.C @@ -0,0 +1,9 @@ +// DR 2237 - Can a template-id name a constructor? +// { dg-options "" } + +template<class T> +struct X { + X<T>(); // { dg-warning "template-id not allowed for constructor" "" { target c++20 } } + X(int); // OK, injected-class-name used + ~X<T>(); // { dg-warning "template-id not allowed for destructor" "" { target c++20 } } +}; diff --git a/gcc/testsuite/g++.dg/DRs/dr2237-3.C b/gcc/testsuite/g++.dg/DRs/dr2237-3.C new file mode 100644 index 00000000000..c8ad6852389 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2237-3.C @@ -0,0 +1,16 @@ +// PR c++/107126 +// { dg-options "" } + +template<typename T> +struct C +{ + ~C(); +}; +template<typename T> +C<T>::~C<T>() // { dg-warning "template-id not allowed for destructor" "" { target c++20 } } +{ +} +int main() +{ + C<int> c;; +} diff --git a/gcc/testsuite/g++.dg/DRs/dr2237-4.C b/gcc/testsuite/g++.dg/DRs/dr2237-4.C new file mode 100644 index 00000000000..a358dd521b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2237-4.C @@ -0,0 +1,11 @@ +// PR c++/97202 +// { dg-options "" } + +template<typename T> +struct F +{ + F<T>(); // { dg-warning "template-id not allowed for constructor" "" { target c++20 } } +}; + +template<typename T> +inline F<T>::F() { } diff --git a/gcc/testsuite/g++.dg/DRs/dr2237.C b/gcc/testsuite/g++.dg/DRs/dr2237.C index f3d6d11e61e..830c8f5a2a6 100644 --- a/gcc/testsuite/g++.dg/DRs/dr2237.C +++ b/gcc/testsuite/g++.dg/DRs/dr2237.C @@ -2,7 +2,7 @@ template<class T> struct X { - X<T>(); // { dg-error "expected" "" { target c++20 } } + X<T>(); // { dg-error "template-id not allowed for constructor" "" { target c++20 } } X(int); // OK, injected-class-name used ~X<T>(); // { dg-error "template-id not allowed for destructor" "" { target c++20 } } }; diff --git a/gcc/testsuite/g++.dg/diagnostic/cdtor-template1.C b/gcc/testsuite/g++.dg/diagnostic/cdtor-template1.C new file mode 100644 index 00000000000..429490708bc --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/cdtor-template1.C @@ -0,0 +1,9 @@ +// PR c++/107126 +// { dg-do compile } +// { dg-options "-Wc++20-compat" } + +template<class T> +struct X { + X<T>(); // { dg-warning "template-id not allowed for constructor" } + ~X<T>(); // { dg-warning "template-id not allowed for destructor" } +}; diff --git a/gcc/testsuite/g++.dg/parse/constructor2.C b/gcc/testsuite/g++.dg/parse/constructor2.C index d620f41e027..e4b2ad3f2fe 100644 --- a/gcc/testsuite/g++.dg/parse/constructor2.C +++ b/gcc/testsuite/g++.dg/parse/constructor2.C @@ -1,11 +1,11 @@ // PR c++/14260 -template <class TClass> -class T -{ -public: - T(short,short f=0) {} - T<TClass>(int f) {} // { dg-error "expected" "" { target c++20 } } - T<TClass>(int f=0,const char* b=0) {} // { dg-error "expected" "" { target c++20 } } -}; +template <class TClass> +class T +{ +public: + T(short,short f=0) {} + T<TClass>(int f) {} // { dg-error "template-id not allowed for constructor" "" { target c++20 } } + T<TClass>(int f=0,const char* b=0) {} // { dg-error "template-id not allowed for constructor" "" { target c++20 } } +}; diff --git a/gcc/testsuite/g++.dg/template/error34.C b/gcc/testsuite/g++.dg/template/error34.C index ab688d9ba8c..921cb8fb729 100644 --- a/gcc/testsuite/g++.dg/template/error34.C +++ b/gcc/testsuite/g++.dg/template/error34.C @@ -3,27 +3,27 @@ template<typename T> struct A { - A<__builtin_offsetof(T, x)>(); // { dg-error "type/value mismatch|offsetof\\(T, x\\)|expected" } + A<__builtin_offsetof(T, x)>(); // { dg-error "type/value mismatch|offsetof\\(T, x\\)|template-id" } }; template<typename T> struct B { - B<__builtin_offsetof(T, x.y)>(); // { dg-error "type/value mismatch|offsetof\\(T, x.y\\)|expected" } + B<__builtin_offsetof(T, x.y)>(); // { dg-error "type/value mismatch|offsetof\\(T, x.y\\)|template-id" } }; template<typename T> struct C { - C<__builtin_offsetof(T, x[6])>(); // { dg-error "type/value mismatch|offsetof\\(T, x\\\[6\\\]\\)|expected" } + C<__builtin_offsetof(T, x[6])>(); // { dg-error "type/value mismatch|offsetof\\(T, x\\\[6\\\]\\)|template-id" } }; template<typename T> struct D { - D<__builtin_offsetof(T, x.y[6].z)>(); // { dg-error "type/value mismatch|offsetof\\(T, x.y\\\[6\\\].z\\)|expected" } + D<__builtin_offsetof(T, x.y[6].z)>(); // { dg-error "type/value mismatch|offsetof\\(T, x.y\\\[6\\\].z\\)|template-id" } }; struct E { int x; }; template<typename T> struct F { - F<__builtin_offsetof(E, x)>(); // { dg-error "type/value mismatch|offsetof\\(E, x\\)|expected" } + F<__builtin_offsetof(E, x)>(); // { dg-error "type/value mismatch|offsetof\\(E, x\\)|template-id" } }; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C index bf418ba48c7..56b4232d04b 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C @@ -4,7 +4,7 @@ template <class T> struct A { - A<T>(); // { dg-error "expected" "" { target c++20 } } + A<T>(); // { dg-error "template-id" "" { target c++20 } } }; template <class T> base-commit: 78005c648921899a674d1e561b49b05ccabedfe0 -- 2.43.0