This is a further fix for P0634. When we have template <typename T> int foo(T::bar);
we shouldn't assume that T::bar is a type because this isn't one of the contexts specified by P0634 -- for that, the function name would have to be qualified. So this patch refines my earlier fix. I should've realized it before, but here we are. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-01-28 Marek Polacek <pola...@redhat.com> PR c++/88358 - name wrongly treated as type. * parser.c (cp_parser_direct_declarator): Don't assume a qualified-id in parameter-list is a type if the function's declarator-id is not qualified. * g++.dg/cpp2a/typename1.C: Add dg-error. * g++.dg/cpp2a/typename13.C: New test. * g++.dg/cpp2a/typename6.C: Make a function name qualified. Add typename. diff --git gcc/cp/parser.c gcc/cp/parser.c index dc9d651308a..16f2a32bc0b 100644 --- gcc/cp/parser.c +++ gcc/cp/parser.c @@ -21107,23 +21107,28 @@ cp_parser_direct_declarator (cp_parser* parser, 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)) + /* ...whose declarator-id is qualified. If it isn't, never + assume the parameters to refer to types. */ + if (qualifying_scope == NULL_TREE) flags &= ~CP_PARSER_FLAGS_TYPENAME_OPTIONAL; + else + { + /* 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; + } } } diff --git gcc/testsuite/g++.dg/cpp2a/typename1.C gcc/testsuite/g++.dg/cpp2a/typename1.C index 833d3b86093..0c1f6309c5b 100644 --- gcc/testsuite/g++.dg/cpp2a/typename1.C +++ gcc/testsuite/g++.dg/cpp2a/typename1.C @@ -6,7 +6,7 @@ template<class T> T::R f(); // Ill-formed (no diagnostic required), attempt to declare // a void variable template -template<class T> void f(T::R); +template<class T> void f(T::R); // { dg-error "declared void" } template <class T> struct A; template <class T> using B = A<T>::U; diff --git gcc/testsuite/g++.dg/cpp2a/typename13.C gcc/testsuite/g++.dg/cpp2a/typename13.C new file mode 100644 index 00000000000..c439f726c5d --- /dev/null +++ gcc/testsuite/g++.dg/cpp2a/typename13.C @@ -0,0 +1,13 @@ +// P0634R3, PR c++/88358 +// { dg-do compile { target c++2a } } + +template <typename T> +int pi(T::your_pi); + +struct Foo { static constexpr int your_pi = 10; }; + +int +main () +{ + return pi<Foo>; +} diff --git gcc/testsuite/g++.dg/cpp2a/typename6.C gcc/testsuite/g++.dg/cpp2a/typename6.C index 49e2235a53d..e96e2ab802c 100644 --- gcc/testsuite/g++.dg/cpp2a/typename6.C +++ gcc/testsuite/g++.dg/cpp2a/typename6.C @@ -55,11 +55,14 @@ struct S2 { // (5.2.4) parameter-declaration in a declarator of a function or function // template declaration whose declarator-id is qualified, // unless that parameter-declaration appears in a default argument -template<typename T> -int fn3 (T::X); + +struct M { + template<typename T> + int fn (T::X); +}; template<typename T> -int fn4 (T::X p) { return p; } +int M::fn (T::X p) { return p; } // (5.2.5) parameter-declaration in a lambda-declarator, // unless that parameter-declaration appears in a default argument @@ -92,7 +95,7 @@ struct S5 { }; template<typename T> -void fn7 (T::X p) +void fn7 (typename T::X p) { int i = static_cast<T::Y>(p); i = dynamic_cast<T::Y>(p);