summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorabutcher <abutcher@138bc75d-0d04-0410-961f-82ee72b054a4>2014-03-28 20:41:45 +0000
committerabutcher <abutcher@138bc75d-0d04-0410-961f-82ee72b054a4>2014-03-28 20:41:45 +0000
commit265a34f4a21ad8f2285f5e849ef700f560795d22 (patch)
tree4b3b534d549cd7d1a2b7dadf8525239410356854 /gcc
parenteecfcba490616b310de58bd38a9716762fa1f716 (diff)
downloadgcc-265a34f4a21ad8f2285f5e849ef700f560795d22.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@208921 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog18
-rw-r--r--gcc/cp/name-lookup.c8
-rw-r--r--gcc/cp/name-lookup.h9
-rw-r--r--gcc/cp/parser.c23
-rw-r--r--gcc/cp/semantics.c1
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr60573.C28
7 files changed, 81 insertions, 11 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 71f94fcf64f..49f0d4af2c5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 53f14f3eee6..0137c3f4a33 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 a63442f85c2..40e0338ca73 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 2e117a53155..5d8446d8640 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index bb5246ab23a..07d10576957 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/ChangeLog b/gcc/testsuite/ChangeLog
index f650e3dabf8..5d9b43358f7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..2f607071c4f
--- /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" }
+};