Re: [PATCH] Fix PR c++/60573

2014-03-28 Thread Adam Butcher

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



[PATCH] Fix PR c++/60573

2014-03-28 Thread Adam Butcher
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.
---
 gcc/cp/name-lookup.c |  8 ++--
 gcc/cp/name-lookup.h |  9 -
 gcc/cp/parser.c  | 23 +--
 gcc/cp/semantics.c   |  1 +
 gcc/testsuite/g++.dg/cpp1y/pr60573.C | 28 
 5 files changed, 60 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr60573.C

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 a63442f..40e0338 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -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.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e729d65..0945bfd 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,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;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 886fbb8..207a42d 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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)
 {
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60573.C 
b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
new file mode 100644

Re: [PATCH] Fix PR c++/60573

2014-03-28 Thread Jason Merrill

OK.

Jason


Re: [PATCH] Fix PR c++/60573

2014-03-27 Thread Jason Merrill

On 03/26/2014 09:12 PM, Adam Butcher wrote:

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


That doesn't seem reliable either, unfortunately; class_shadowed is 
populated when names are looked up, so a declarator that refers to a 
type member of B will cause scope-class_shadowed to be non-null.


Jason



[PATCH] Fix PR c++/60573

2014-03-27 Thread Adam Butcher
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.

PR c++/60573
* g++.dg/cpp1y/pr60573.C: New testcase.
---
 gcc/cp/name-lookup.h |  6 +-
 gcc/cp/parser.c  | 23 +--
 gcc/cp/pt.c  |  5 -
 gcc/cp/semantics.c   |  1 +
 gcc/testsuite/g++.dg/cpp1y/pr60573.C | 28 
 5 files changed, 55 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr60573.C

diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index a63442f..9e5d812 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -255,7 +255,11 @@ struct GTY(()) cp_binding_level {
   unsigned more_cleanups_ok : 1;
   unsigned have_cleanups : 1;
 
-  /* 24 bits left to fill a 32-bit word.  */
+  /* Set if this scope is of sk_class kind and is the defining
+ scope for this_entity.  */
+  unsigned scope_defines_class_p : 1;
+
+  /* 23 bits left to fill a 32-bit word.  */
 };
 
 /* The binding level currently in effect.  */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e729d65..4919a67 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,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-scope_defines_class_p)
{
  parent_scope = scope;
  scope = scope-level_chain;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c791d03..90faeec 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8905,9 +8905,12 @@ 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 886fbb8..deba2ab 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2777,6 +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;
 
   if (flag_pack_struct)
 {
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr60573.C 
b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
new file mode 100644
index 000..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 

Re: [PATCH] Fix PR c++/60573

2014-03-27 Thread Adam Butcher

On 2014-03-27 20:45, Adam Butcher wrote:

@@ -8905,9 +8905,12 @@ 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;



I meant current_binding_level here; but I'm not sure it's necessary 
here at all.




Re: [PATCH] Fix PR c++/60573

2014-03-27 Thread Adam Butcher

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.




Re: [PATCH] Fix PR c++/60573

2014-03-26 Thread Jason Merrill

On 03/25/2014 03:48 PM, Adam Butcher wrote:

I don't follow.  Are you suggesting a case like the following?

   struct A
   {
 struct X
 {
   struct B
   {
 void foo(auto);
   };
 };

 void X::B::foo(auto) {}  // { dg-error cannot define }
   };


I meant

  struct A
  {
struct X
{
  struct B
  {
void foo(auto);
  };

  void B::foo(auto) {}  // { dg-error cannot define }
};
  };

Here we push both A and X for the declarator.  When we get to the pushed 
X, we see that the enclosing scope is A, so we break out of the loop and 
don't pop either of the pushed scopes.


Jason



Re: [PATCH] Fix PR c++/60573

2014-03-26 Thread Adam Butcher

On 2014-03-26 15:17, Jason Merrill wrote:


I meant

  struct A
  {
struct X
{
  struct B
  {
void foo(auto);
  };

  void B::foo(auto) {}  // { dg-error cannot define }
};
  };

Here we push both A and X for the declarator.  When we get to the
pushed X, we see that the enclosing scope is A, so we break out of 
the

loop and don't pop either of the pushed scopes.

Thought I was probably being dense!  :)  Yes, that will be broken with 
the current patch.  Continuing the loop based on TYPE_BEING_DEFINED 
might do the trick.  I'll try to have a look later.


Cheers,
Adam



Re: [PATCH] Fix PR c++/60573

2014-03-26 Thread Adam Butcher

On 2014-03-25 15:48, Jason Merrill wrote:


I think we need some way to designate a scope that actually
corresponds to a class-specifier.


Agreed.  I'll look into it.

Adam


[PATCH] Fix PR c++/60573

2014-03-26 Thread Adam Butcher
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 000..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



Re: [PATCH] Fix PR c++/60573

2014-03-25 Thread Adam Butcher

On 2014-03-25 15:48, Jason Merrill wrote:

On 03/18/2014 10:46 PM, Adam Butcher wrote:

+ if (TYPE_BEING_DEFINED (scope-this_entity))
+   if (scope-level_chain == 0
+   || scope-this_entity != scope-level_chain-this_entity)
+ break;


I don't think this is an adequate test; if you have another class
wrapping B, you'll have two levels of context pushed for the
declarator, so the this_entities will compare unequal.  I think we
need some way to designate a scope that actually corresponds to a
class-specifier.


I don't follow.  Are you suggesting a case like the following?

  struct A
  {
struct X
{
  struct B
  {
void foo(auto);
  };
};

void X::B::foo(auto) {}  // { dg-error cannot define }
  };

If so, it is handled.  The code you are referring to is within a 
level_chain traversal loop so handles arbitrary levels of pushed 
context.  The end result is the same though; we arrive at an 'A::' scope 
that is not the defining class scope but has the same 'this_entity' as 
it (so TYPE_BEING_DEFINED returns true).  The scope chain is as if the 
following was used to declare it:


  struct A
  {
...
void A::X::B::foo(auto);
  };

It is the two levels of 'A' entity scopes that caused the ICE due the 
previous version of the loop stopping to inject the template parameter 
list between the 'A::' and the 'X::', rather than unwinding back to the 
scope defining 'A'.


Apologies if I've completely misunderstood your point here.  I've got a 
feeling that I may have.


Adam


Re: [PATCH] Fix PR c++/60573

2014-03-25 Thread Jason Merrill

On 03/18/2014 10:46 PM, Adam Butcher wrote:

+ if (TYPE_BEING_DEFINED (scope-this_entity))
+   if (scope-level_chain == 0
+   || scope-this_entity != scope-level_chain-this_entity)
+ break;


I don't think this is an adequate test; if you have another class 
wrapping B, you'll have two levels of context pushed for the declarator, 
so the this_entities will compare unequal.  I think we need some way to 
designate a scope that actually corresponds to a class-specifier.


Jason



Re: [PATCH] Fix PR c++/60573

2014-03-24 Thread Jason Merrill

On 03/18/2014 10:46 PM, Adam Butcher wrote:

- while (scope-kind == sk_class
- !TYPE_BEING_DEFINED (scope-this_entity))


Does it work to just change TYPE_BEING_DEFINED to currently_open_class?

Jason



Re: [PATCH] Fix PR c++/60573

2014-03-24 Thread Adam Butcher

On 2014-03-24 17:23, Jason Merrill wrote:

On 03/18/2014 10:46 PM, Adam Butcher wrote:

- while (scope-kind == sk_class
- !TYPE_BEING_DEFINED (scope-this_entity))


Does it work to just change TYPE_BEING_DEFINED to 
currently_open_class?


No.  The object referred to by 'scope-this_entity' is the same for 
each of the two levels, so unless there's something else I can pass to 
'currently_open_class', the result will be equivalent; the issue is that 
the class being referred to *is* being defined, but I need to skip over 
the second class-scope for that type to arrive at the defining scope 
level.


Adam


[PATCH] Fix PR c++/60573

2014-03-18 Thread Adam Butcher
PR c++/60573
* parser.c (synthesize_implicit_template_parm): Handle the fact that
nested class member declarations erroneously appearing in an enclosing
class contain an addition scope level for the class being defined.

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

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 46e2453..36872c9 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -32006,9 +32006,23 @@ synthesize_implicit_template_parm  (cp_parser *parser)
must be injected in the scope of 'B', just beyond the scope of 'A'
introduced by 'A::'.  */
 
- while (scope-kind == sk_class
- !TYPE_BEING_DEFINED (scope-this_entity))
+ while (scope-kind == sk_class)
{
+ /* In valid cases where the class being defined is reached, we're
+at the point where the template argument list should be
+injected for a generic member function.  In the erroneous case
+of generic member function of a nested class being declared in
+the enclosing class, an additional class scope for the
+enclosing class has been pushed by push_nested_class via
+push_scope in cp_parser_direct_declarator.  This additional
+scope needs to be skipped to reach the class definition scope
+where the template argument list should be injected.  */
+
+ if (TYPE_BEING_DEFINED (scope-this_entity))
+   if (scope-level_chain == 0
+   || scope-this_entity != scope-level_chain-this_entity)
+ break;
+
  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 000..7f56ff4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr60573.C
@@ -0,0 +1,13 @@
+// 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 }
+};
-- 
1.9.0