diff mbox

Fix PR c++/60573

Message ID a4ff0d4d9418ea7110a3e8a427307a50@imap.force9.net
State New
Headers show

Commit Message

Adam Butcher March 28, 2014, 10:01 a.m. UTC
On 2014-03-27 21:16, Adam Butcher wrote:
> On 2014-03-27 20:45, Adam Butcher wrote:
>> PR c++/60573
>> * name-lookup.h (cp_binding_level): New field scope_defines_class_p.
>> * semantics.c (begin_class_definition): Set scope_defines_class_p.
>> * pt.c (instantiate_class_template_1): Likewise.
>> * parser.c (synthesize_implicit_template_parm): Use 
>> cp_binding_level::
>> scope_defines_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.
>>
> Still got issues with this.  It fails on out-of-line defs.  I'll have
> another look.

Turns out the solution was OK but I didn't account for the 
class-defining scope being reused for subsequent out-of-line 
declarations.  I've made 'scope_defines_class_p' in to the now transient 
'defining_class_p' predicate which is reset on leaving scope.  I've 
ditched the 'scope_' prefix and also ditched the modifications to 
'instantiate_class_template_1'.

The patch delta is included below (but will probably be munged by my 
webmail client).  I'll reply to this with the full patch.

There is also the fix for PR c++/60626 
(http://gcc.gnu.org/ml/gcc-patches/2014-03/msg01294.html) that deals 
with another form of erroneous generic function declarations with nested 
class scope.

Cheers,
Adam
diff mbox

Patch

diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 53f14f3..0137c3f 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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)
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 9e5d812..40e0338 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -255,9 +255,12 @@  struct GTY(()) cp_binding_level {
    unsigned more_cleanups_ok : 1;
    unsigned have_cleanups : 1;

-  /* Set if this scope is of sk_class kind and is the defining
-     scope for this_entity.  */
-  unsigned scope_defines_class_p : 1;
+  /* 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.  */
  };
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 4919a67..0945bfd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -32027,7 +32027,7 @@  synthesize_implicit_template_parm  (cp_parser 
*parser)
             declarator should be injected into the scope of 'A' as if 
the
             ill-formed template was specified explicitly.  */

-         while (scope->kind == sk_class && 
!scope->scope_defines_class_p)
+         while (scope->kind == sk_class && !scope->defining_class_p)
             {
               parent_scope = scope;
               scope = scope->level_chain;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 90faeec..c791d03 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8905,12 +8905,9 @@  instantiate_class_template_1 (tree type)
      return type;

    /* Now we're really doing the instantiation.  Mark the type as in
-     the process of being defined...  */
+     the process of being defined.  */
    TYPE_BEING_DEFINED (type) = 1;

-  /* ... and the scope defining it.  */
-  class_binding_level->scope_defines_class_p = 1;
-
    /* We may be in the middle of deferred access check.  Disable
       it now.  */
    push_deferring_access_checks (dk_no_deferred);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index deba2ab..207a42d 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2777,7 +2777,7 @@  begin_class_definition (tree t)
    maybe_process_partial_specialization (t);
    pushclass (t);
    TYPE_BEING_DEFINED (t) = 1;
-  class_binding_level->scope_defines_class_p = 1;
+  class_binding_level->defining_class_p = 1;

    if (flag_pack_struct)
      {