This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR c++/60573
- From: Adam Butcher <adam at jessamine dot co dot uk>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org, Volker Reichelt <reichelt at gcc dot gnu dot org>, Adam Butcher <adam at jessamine dot co dot uk>
- Date: Thu, 27 Mar 2014 01:12:25 +0000
- Subject: [PATCH] Fix PR c++/60573
- Authentication-results: sourceware.org; auth=none
- References: <a19a69543f8f23737047ab53b0f22b5c at imap dot force9 dot net>
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