This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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.
commit 5d594c4a4616821068b111489b26a88183d6eb22
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jul 17 00:45:54 2012 -0400

    	PR c++/53549
    	* parser.c (cp_parser_class_head): Call xref_basetypes here.
    	(cp_parser_class_specifier_1): Not here.
    	* pt.c (tsubst_decl) [USING_DECL]: Check uses_template_parms
    	as well as DECL_DEPENDENT_P.

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 1428a26..df23299 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2008,7 +2008,7 @@ static tree cp_parser_class_name
 static tree cp_parser_class_specifier
   (cp_parser *);
 static tree cp_parser_class_head
-  (cp_parser *, bool *, tree *);
+  (cp_parser *, bool *);
 static enum tag_types cp_parser_class_key
   (cp_parser *);
 static void cp_parser_member_specification_opt
@@ -17961,15 +17961,13 @@ cp_parser_class_specifier_1 (cp_parser* parser)
   bool saved_in_unbraced_linkage_specification_p;
   tree old_scope = NULL_TREE;
   tree scope = NULL_TREE;
-  tree bases;
   cp_token *closing_brace;
 
   push_deferring_access_checks (dk_no_deferred);
 
   /* Parse the class-head.  */
   type = cp_parser_class_head (parser,
-			       &nested_name_specifier_p,
-			       &bases);
+			       &nested_name_specifier_p);
   /* If the class-head was a semantic disaster, skip the entire body
      of the class.  */
   if (!type)
@@ -17986,18 +17984,6 @@ cp_parser_class_specifier_1 (cp_parser* parser)
       return error_mark_node;
     }
 
-  /* Process the base classes. If they're invalid, skip the 
-     entire class body.  */
-  if (!xref_basetypes (type, bases))
-    {
-      /* Consuming the closing brace yields better error messages
-         later on.  */
-      if (cp_parser_skip_to_closing_brace (parser))
-	cp_lexer_consume_token (parser->lexer);
-      pop_deferring_access_checks ();
-      return error_mark_node;
-    }
-
   /* Issue an error message if type-definitions are forbidden here.  */
   cp_parser_check_type_definition (parser);
   /* Remember that we are defining one more class.  */
@@ -18283,14 +18269,14 @@ cp_parser_class_specifier (cp_parser* parser)
 
 static tree
 cp_parser_class_head (cp_parser* parser,
-		      bool* nested_name_specifier_p,
-		      tree *bases)
+		      bool* nested_name_specifier_p)
 {
   tree nested_name_specifier;
   enum tag_types class_key;
   tree id = NULL_TREE;
   tree type = NULL_TREE;
   tree attributes;
+  tree bases;
   cp_virt_specifiers virt_specifiers = VIRT_SPEC_UNSPECIFIED;
   bool template_id_p = false;
   bool qualified_p = false;
@@ -18307,8 +18293,6 @@ cp_parser_class_head (cp_parser* parser,
   num_templates = 0;
   parser->colon_corrects_to_scope_p = false;
 
-  *bases = NULL_TREE;
-
   /* Look for the class-key.  */
   class_key = cp_parser_class_key (parser);
   if (class_key == none_type)
@@ -18671,7 +18655,15 @@ cp_parser_class_head (cp_parser* parser,
 
   /* Get the list of base-classes, if there is one.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
-    *bases = cp_parser_base_clause (parser);
+    bases = cp_parser_base_clause (parser);
+  else
+    bases = NULL_TREE;
+
+  /* If we're really defining a class, process the base classes.
+     If they're invalid, fail.  */
+  if (type && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
+      && !xref_basetypes (type, bases))
+    type = NULL_TREE;
 
  done:
   /* Leave the scope given by the nested-name-specifier.  We will
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 95c6464..542f57a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10235,8 +10235,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
       break;
 
     case USING_DECL:
-      /* We reach here only for member using decls.  */
-      if (DECL_DEPENDENT_P (t))
+      /* We reach here only for member using decls.  We also need to check
+	 uses_template_parms because DECL_DEPENDENT_P is not set for a
+	 using-declaration that designates a member of the current
+	 instantiation (c++/53549).  */
+      if (DECL_DEPENDENT_P (t)
+	  || uses_template_parms (USING_DECL_SCOPE (t)))
 	{
 	  r = do_class_using_decl
 	    (tsubst_copy (USING_DECL_SCOPE (t), args, complain, in_decl),
diff --git a/gcc/testsuite/g++.dg/parse/crash35.C b/gcc/testsuite/g++.dg/parse/crash35.C
index 4937cdc..161edad 100644
--- a/gcc/testsuite/g++.dg/parse/crash35.C
+++ b/gcc/testsuite/g++.dg/parse/crash35.C
@@ -3,5 +3,5 @@
 
 struct a {};
 
-class foo : public a, a
-{ /* { dg-error "duplicate base type|at end of input" } */
+class foo : public a, a		// { dg-error "duplicate base" }
+{ /* { dg-error "at end of input" } */
diff --git a/gcc/testsuite/g++.dg/template/current-inst1.C b/gcc/testsuite/g++.dg/template/current-inst1.C
new file mode 100644
index 0000000..8f42ef8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/current-inst1.C
@@ -0,0 +1,19 @@
+// PR c++/53549
+
+template<typename T>
+struct C2
+{
+  int operator()();
+
+  template<int> struct F2;
+};
+
+
+template<typename T>
+template<int I>
+struct C2<T>::F2 : C2<T>
+{
+  using C2<T>::operator();
+};
+
+C2<int>::F2<42> f;
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;
 };

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]