Patchwork C++ PATCH for c++/53549 (ICE with using-declaration in nested class derived from enclosing class template)

login
register
mail settings
Submitter Jason Merrill
Date July 17, 2012, 6:04 p.m.
Message ID <5005A93E.3070801@redhat.com>
Download mbox | patch
Permalink /patch/171523/
State New
Headers show

Comments

Jason Merrill - July 17, 2012, 6:04 p.m.
For C2<T> to be considered the "current instantiation", we need to call 
xref_basetypes while we're still pushed into its scope.  So we can 
actually simplify the code by moving the call into cp_parser_class_head.

Once we've fixed that, we need to fix tsubst_decl to handle USING_DECLs 
for members of the current instantiation, since the scope can be a 
dependent type even though we can do name lookup in it.

The discussion of the PR also pointed out that EDG rejects code like

template <class T> struct A
{
   struct B : A { };
};

because A<T> is not complete yet.  This makes sense to me, so I've added 
this diagnostic as a pedwarn (so code that uses this pattern will 
continue to compile for now).

Tested x86_64-pc-linux-gnu, applying the first patch to trunk and 4.7, 
the second to trunk only.

Patch

commit 22ef026b9bac683273c17d80170be4721241b706
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jul 17 06:15:20 2012 -0400

    	* decl.c (xref_basetypes): Complain about incomplete template base.
    	* class.c (finish_struct): Adjust variants in templates, too.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 3877a27..82c28fa 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6325,6 +6325,15 @@  finish_struct (tree t, tree attributes)
 
       /* Remember current #pragma pack value.  */
       TYPE_PRECISION (t) = maximum_field_alignment;
+
+      /* Fix up any variants we've already built.  */
+      for (x = TYPE_NEXT_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
+	{
+	  TYPE_SIZE (x) = TYPE_SIZE (t);
+	  TYPE_SIZE_UNIT (x) = TYPE_SIZE_UNIT (t);
+	  TYPE_FIELDS (x) = TYPE_FIELDS (t);
+	  TYPE_METHODS (x) = TYPE_METHODS (t);
+	}
     }
   else
     finish_struct_1 (t);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 842c2d8..84b78f6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11843,7 +11843,14 @@  xref_basetypes (tree ref, tree base_list)
     {
       tree basetype = TREE_VALUE (*basep);
 
-      if (!(processing_template_decl && uses_template_parms (basetype))
+      /* The dependent_type_p call below should really be dependent_scope_p
+	 so that we give a hard error about using an incomplete type as a
+	 base, but we allow it with a pedwarn for backward
+	 compatibility.  */
+      if (processing_template_decl
+	  && CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype))
+	cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN);
+      if (!dependent_type_p (basetype)
 	  && !complete_type_or_else (basetype, NULL))
 	/* An incomplete type.  Remove it from the list.  */
 	*basep = TREE_CHAIN (*basep);
diff --git a/gcc/testsuite/g++.dg/template/inherit8.C b/gcc/testsuite/g++.dg/template/inherit8.C
index a9b2bdb..3176dc0 100644
--- a/gcc/testsuite/g++.dg/template/inherit8.C
+++ b/gcc/testsuite/g++.dg/template/inherit8.C
@@ -4,9 +4,9 @@  template <typename T>
 struct A
 {
   template <typename U>
-  struct B : public A <B<U> >
+  struct B : public A <B<U> >	// { dg-error "declaration" }
   {
-    struct C : public B<U>
+    struct C : public B<U>	// { dg-error "incomplete" }
     {
     };
   };
diff --git a/gcc/testsuite/g++.dg/template/using21.C b/gcc/testsuite/g++.dg/template/using21.C
index 7f61f85..65313aa 100644
--- a/gcc/testsuite/g++.dg/template/using21.C
+++ b/gcc/testsuite/g++.dg/template/using21.C
@@ -4,25 +4,34 @@ 
 template<typename T>
 struct A
 {
-    int foo;
+  int foo;
 
-    struct B : A<T>
-    {
-        using A::foo;
-    };
+  struct B;
+  struct C;
+  struct D;
+  struct E;
+};
 
-    struct C : A
-    {
-        using A::foo;
-    };
+template <class T>
+struct A<T>::B : A<T>
+{
+  using A::foo;
+};
 
-    struct D : A<T>
-    {
-	using A<T>::foo;
-    };
+template <class T>
+struct A<T>::C : A
+{
+  using A::foo;
+};
+
+template <class T>
+struct A<T>::D : A<T>
+{
+  using A<T>::foo;
+};
 
-    struct E : A
-    {
-	using A<T>::foo;
-    };
+template <class T>
+struct A<T>::E : A
+{
+  using A<T>::foo;
 };
diff --git a/gcc/testsuite/g++.dg/template/using22.C b/gcc/testsuite/g++.dg/template/using22.C
index b456e62..9ea3d8a 100644
--- a/gcc/testsuite/g++.dg/template/using22.C
+++ b/gcc/testsuite/g++.dg/template/using22.C
@@ -6,28 +6,39 @@  template <class T> struct Z {};
 template<typename T>
 struct A
 {
-    struct B : A<T>
-    {
-        using A::nonexist; // { dg-error "no members matching" }
-    };
+  struct B;
+  struct C;
+  struct D;
+  struct E;
+  struct F;
+};
+
+template <class T>
+struct A<T>::B : A<T>
+{
+  using A::nonexist; // { dg-error "no members matching" }
+};
 
-    struct C : A
-    {
-        using A::nonexist; // { dg-error "no members matching" }
-    };
+template <class T>
+struct A<T>::C : A
+{
+  using A::nonexist; // { dg-error "no members matching" }
+};
 
-    struct D : A<T>
-    {
-    	using A<T>::nonexist; // { dg-error "no members matching" }
-    };
+template <class T>
+struct A<T>::D : A<T>
+{
+  using A<T>::nonexist; // { dg-error "no members matching" }
+};
 
-    struct E : A
-    {
-    	using A<T>::nonexist; // { dg-error "no members matching" }
-    };
+template <class T>
+struct A<T>::E : A
+{
+  using A<T>::nonexist; // { dg-error "no members matching" }
+};
 
-    struct F : Z<T>
-    {
-	using Z<T>::nonexist;
-    };
+template <class T>
+struct A<T>::F : Z<T>
+{
+  using Z<T>::nonexist;
 };