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);

Reply via email to