Since C++20 P0634R3 we sometimes treat certain qualified-ids as types, so that the user doesn't have to type 'typename'. But this was broken for this case:
template<typename T> T::type N::v(T::value); which, if T::value is a type, is a function template declaration. But if T::value is a value, it's a variable template definition. So we can't always assume T::value is a type. This patch fixes it according to the proposed resolution discussed on the core reflector (2018-10-29) -- perform name lookup to see if N::v is one or more function templates, and if it isn't, don't consider 'typename' optional in the parameter list. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-01-23 Marek Polacek <pola...@redhat.com> PR c++/88757 - qualified name treated wrongly as type. * parser.c (cp_parser_direct_declarator): Don't treat qualified-ids in parameter-list as types if name lookup for declarator-id didn't find one or more function templates. * g++.dg/cpp0x/dependent2.C: New test. * g++.dg/cpp2a/typename10.C: Remove dg-error. * g++.dg/cpp2a/typename12.C: New test. * g++.dg/template/static30.C: Remove dg-error. diff --git gcc/cp/parser.c gcc/cp/parser.c index 7d7b0292650..dc9d651308a 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -21098,6 +21098,33 @@ cp_parser_direct_declarator (cp_parser* parser, if (pack_expansion_p) maybe_warn_variadic_templates (); + + /* We're looking for this case in [temp.res]: + A qualified-id is assumed to name a type if [...] + - it is a decl-specifier of the decl-specifier-seq of a + parameter-declaration in a declarator of a function or + function template declaration, ... */ + if (cxx_dialect >= cxx2a + && (flags & CP_PARSER_FLAGS_TYPENAME_OPTIONAL) + && declarator->kind == cdk_id + /* ...whose declarator-id is qualified. */ + && qualifying_scope != NULL_TREE + && !at_class_scope_p () + && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + /* Now we have something like + template <typename T> int C::x(S::p); + which can be a function template declaration or a + variable template definition. If name lookup for + the declarator-id C::x finds one or more function + templates, assume S::p to name a type. Otherwise, + don't. */ + tree decl + = cp_parser_lookup_name_simple (parser, unqualified_name, + token->location); + if (!is_overloaded_fn (decl)) + flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL; + } } handle_declarator:; diff --git gcc/testsuite/g++.dg/cpp0x/dependent2.C gcc/testsuite/g++.dg/cpp0x/dependent2.C new file mode 100644 index 00000000000..a0740d404a3 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/dependent2.C @@ -0,0 +1,10 @@ +// PR c++/88757 +// { dg-do compile { target c++11 } } + +template <class T> struct C { + static int x; +}; +template <class U> struct S { + static const int size = 1; +}; +template <class T> int C<T>::x(S<T>::size); diff --git gcc/testsuite/g++.dg/cpp2a/typename10.C gcc/testsuite/g++.dg/cpp2a/typename10.C index fa2cd000b5d..1413268ba16 100644 --- gcc/testsuite/g++.dg/cpp2a/typename10.C +++ gcc/testsuite/g++.dg/cpp2a/typename10.C @@ -11,7 +11,7 @@ namespace N2 { template<typename T> extern T::type v; // #1a //template<typename T> T::type v(typename T::value); // #1b } -template<typename T> T::type N2::v(T::value); // { dg-error "" } +template<typename T> T::type N2::v(T::value); namespace A { inline namespace B { template<typename T> int f(typename T::foo); } diff --git gcc/testsuite/g++.dg/cpp2a/typename12.C gcc/testsuite/g++.dg/cpp2a/typename12.C new file mode 100644 index 00000000000..97962e53d65 --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/typename12.C @@ -0,0 +1,20 @@ +// P0634R3 +// { dg-do compile { target c++2a } } + +struct W { + template<typename T> + static int fn1 (T::X); + template<typename T> + static int fn2 (T::X); + template<typename T> + static int fn2 (T::X, int); +}; + +template<typename T> +int W::fn1 (T::X p) { return p; } + +template<typename T> +int W::fn2 (T::X p) { return p; } + +template<typename T> +int fn2 (typename T::X p) { return p; } diff --git gcc/testsuite/g++.dg/template/static30.C gcc/testsuite/g++.dg/template/static30.C index 8b8637a1abe..07dafe23ffa 100644 --- gcc/testsuite/g++.dg/template/static30.C +++ gcc/testsuite/g++.dg/template/static30.C @@ -6,5 +6,5 @@ template <int> struct A static const int i2; }; -template <int N> const int A<N>::i1(A<N>::i); // { dg-error "no declaration matches" "" { target c++2a } } +template <int N> const int A<N>::i1(A<N>::i); template <int N> const int A<N>::i2(3, A<N>::i); // { dg-error "expression list" }