]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/60573 ([c++1y] ICE with defining generic function of nested class in class...
authorAdam Butcher <abutcher@gcc.gnu.org>
Fri, 28 Mar 2014 20:41:45 +0000 (20:41 +0000)
committerAdam Butcher <abutcher@gcc.gnu.org>
Fri, 28 Mar 2014 20:41:45 +0000 (20:41 +0000)
Fix PR c++/60573

PR c++/60573
* name-lookup.h (cp_binding_level): New transient field defining_class_p
to indicate whether a scope is in the process of defining a class.
* semantics.c (begin_class_definition): Set defining_class_p.
* name-lookup.c (leave_scope): Reset defining_class_p.
* parser.c (synthesize_implicit_template_parm): Use cp_binding_level::
defining_class_p 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.

From-SVN: r208921

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp1y/pr60573.C [new file with mode: 0644]

index 71f94fcf64ff546d20734d522b81a8d839fadbe1..49f0d4af2c502f6feb336ee773e49ba1e4ceb80d 100644 (file)
@@ -1,6 +1,20 @@
+2014-03-28  Adam Butcher  <adam@jessamine.co.uk>
+
+       PR c++/60573
+       * name-lookup.h (cp_binding_level): New transient field defining_class_p
+       to indicate whether a scope is in the process of defining a class.
+       * semantics.c (begin_class_definition): Set defining_class_p.
+       * name-lookup.c (leave_scope): Reset defining_class_p.
+       * parser.c (synthesize_implicit_template_parm): Use cp_binding_level::
+       defining_class_p 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.
+
 2014-03-26  Fabien ChĂȘne  <fabien@gcc.gnu.org>
-        PR c++/52369
-        * cp/method.c (walk_field_subobs): improve the diagnostic
+
+       PR c++/52369
+       * cp/method.c (walk_field_subobs): improve the diagnostic
        locations for both REFERENCE_TYPEs and non-static const members.
        * cp/init.c (diagnose_uninitialized_cst_or_ref_member): use %q#D
        instead of %qD to be consistent with the c++11 diagnostic.
index 53f14f3eee618eca2158cf9a55816f3ec28553a2..0137c3f4a337019c974b9484e4231e445652a24c 100644 (file)
@@ -1630,10 +1630,14 @@ leave_scope (void)
       free_binding_level = scope;
     }
 
-  /* Find the innermost enclosing class scope, and reset
-     CLASS_BINDING_LEVEL appropriately.  */
   if (scope->kind == sk_class)
     {
+      /* Reset DEFINING_CLASS_P to allow for reuse of a
+        class-defining scope in a non-defining context.  */
+      scope->defining_class_p = 0;
+
+      /* Find the innermost enclosing class scope, and reset
+        CLASS_BINDING_LEVEL appropriately.  */
       class_binding_level = NULL;
       for (scope = current_binding_level; scope; scope = scope->level_chain)
        if (scope->kind == sk_class)
index a63442f85c2064c1fc4f034efc8a6b32ee4a7b65..40e0338ca7337ce5ca7bb22f56c9bd9a3614412d 100644 (file)
@@ -255,7 +255,14 @@ struct GTY(()) cp_binding_level {
   unsigned more_cleanups_ok : 1;
   unsigned have_cleanups : 1;
 
-  /* 24 bits left to fill a 32-bit word.  */
+  /* Transient state set if this scope is of sk_class kind
+     and is in the process of defining 'this_entity'.  Reset
+     on leaving the class definition to allow for the scope
+     to be subsequently re-used as a non-defining scope for
+     'this_entity'.  */
+  unsigned defining_class_p : 1;
+
+  /* 23 bits left to fill a 32-bit word.  */
 };
 
 /* The binding level currently in effect.  */
index 2e117a53155c0feeec84154e91bb627ddffe1e1b..5d8446d86405b5295edb53251a9d4619c2d190e3 100644 (file)
@@ -31999,7 +31999,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:
 
@@ -32010,12 +32010,23 @@ 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.  */
+
+         while (scope->kind == sk_class && !scope->defining_class_p)
            {
              parent_scope = scope;
              scope = scope->level_chain;
index bb5246ab23aa625f136b4a9b2fe45abbe0fc83c9..07d105769576f4cc85983809a9d92a2b49ede21c 100644 (file)
@@ -2777,6 +2777,7 @@ begin_class_definition (tree t)
   maybe_process_partial_specialization (t);
   pushclass (t);
   TYPE_BEING_DEFINED (t) = 1;
+  class_binding_level->defining_class_p = 1;
 
   if (flag_pack_struct)
     {
index f650e3dabf8f33538aa74951d91cb04d1d387bb7..5d9b43358f707e8432469cb8cc9bbc146d0f46d8 100644 (file)
@@ -1,3 +1,8 @@
+2014-03-28  Adam Butcher  <adam@jessamine.co.uk>
+
+       PR c++/60573
+       * g++.dg/cpp1y/pr60573.C: New testcase.
+
 2014-03-28  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/60693
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60573.C b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
new file mode 100644 (file)
index 0000000..2f60707
--- /dev/null
@@ -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" }
+};