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