PR c++/60573
        * parser.c (synthesize_implicit_template_parm): Use cp_binding_level::
        class_shadowed rather than TYPE_BEING_DEFINED as the predicate for
        unwinding to class-defining scope to handle the erroneous definition of
        a generic function of an arbitrarily nested class within an enclosing
        class.

        PR c++/60573
        * g++.dg/cpp1y/pr60573.C: New testcase.
---
 gcc/cp/parser.c                      | 30 ++++++++++++++++++++++++------
 gcc/testsuite/g++.dg/cpp1y/pr60573.C | 28 ++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr60573.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e729d65..2130bcd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -32000,7 +32000,7 @@ synthesize_implicit_template_parm  (cp_parser *parser)
        {
          /* If not defining a class, then any class scope is a scope level in
             an out-of-line member definition.  In this case simply wind back
-            beyond the first such scope to inject the template argument list.
+            beyond the first such scope to inject the template parameter list.
             Otherwise wind back to the class being defined.  The latter can
             occur in class member friend declarations such as:
 
@@ -32011,12 +32011,30 @@ synthesize_implicit_template_parm  (cp_parser *parser)
                 friend void A::foo (auto);
               };
 
-           The template argument list synthesized for the friend declaration
-           must be injected in the scope of 'B', just beyond the scope of 'A'
-           introduced by 'A::'.  */
+           The template parameter list synthesized for the friend declaration
+           must be injected in the scope of 'B'.  This can also occur in
+           erroneous cases such as:
 
-         while (scope->kind == sk_class
-                && !TYPE_BEING_DEFINED (scope->this_entity))
+              struct A {
+                struct B {
+                  void foo (auto);
+                };
+                void B::foo (auto) {}
+              };
+
+            Here the attempted definition of 'B::foo' within 'A' is ill-formed
+            but, nevertheless, the template parameter list synthesized for the
+            declarator should be injected into the scope of 'A' as if the
+            ill-formed template was specified explicitly.
+
+            Note: cp_binding_level::class_shadowed is used as a predicate to
+            indicate whether a class scope is a class-defining scope.  We stop
+            at the first such scope as this will be the currently open class
+            definition into which the function being declared will be appended;
+            and therefore the scope into which the synthesized template
+            parameter list for the declarator should be injected.  */
+
+         while (scope->kind == sk_class && !scope->class_shadowed)
            {
              parent_scope = scope;
              scope = scope->level_chain;
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60573.C 
b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
new file mode 100644
index 0000000..2f60707
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
@@ -0,0 +1,28 @@
+// PR c++/60573
+// { dg-do compile { target c++1y } }
+// { dg-options "" }
+
+struct A
+{
+  struct B
+  {
+    void foo(auto);
+  };
+
+  void B::foo(auto) {}  // { dg-error "cannot define" }
+
+  struct X
+  {
+    struct Y
+    {
+      struct Z
+      {
+        void foo(auto);
+      };
+    };
+
+    void Y::Z::foo(auto) {}  // { dg-error "cannot define" }
+  };
+
+  void X::Y::Z::foo(auto) {}  // { dg-error "cannot define" }
+};
-- 
1.9.0

Reply via email to