Patchwork C++ PATCH to handling of fields with incomplete type

login
register
mail settings
Submitter Jason Merrill
Date June 7, 2013, 2:48 a.m.
Message ID <51B14A08.4060303@redhat.com>
Download mbox | patch
Permalink /patch/249586/
State New
Headers show

Comments

Jason Merrill - June 7, 2013, 2:48 a.m.
A while back I noticed an error-recovery issue with fields of incomplete 
type: later references to such fields would give an error that the name 
was undeclared, which is not the case.  This patch improves that situation.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit cf2d44c5b95890d6b7de7f4cc48284cc9e528683
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Jun 6 15:19:09 2013 -0400

    	* decl.c (grokdeclarator): Keep a decl with error type.
    	(grokfield, grokbitfield): Likewise.
    	* pt.c (instantiate_class_template_1): Likewise.
    	(tsubst_decl): Drop redundant error.
    	* class.c (walk_subobject_offsets): Handle erroneous fields.
    	* typeck2.c (process_init_constructor_record): Likewise.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 40e6d3e..286164d 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3779,7 +3779,9 @@  walk_subobject_offsets (tree type,
 
       /* Iterate through the fields of TYPE.  */
       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
-	if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field))
+	if (TREE_CODE (field) == FIELD_DECL
+	    && TREE_TYPE (field) != error_mark_node
+	    && !DECL_ARTIFICIAL (field))
 	  {
 	    tree field_offset;
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index c37b4fe..7825c73 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -10530,21 +10530,13 @@  grokdeclarator (const cp_declarator *declarator,
 		 && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
 	  {
 	    if (unqualified_id)
-	      error ("field %qD has incomplete type", unqualified_id);
+	      error ("field %qD has incomplete type %qT",
+		     unqualified_id, type);
 	    else
 	      error ("name %qT has incomplete type", type);
 
-	    /* If we're instantiating a template, tell them which
-	       instantiation made the field's type be incomplete.  */
-	    if (current_class_type
-		&& TYPE_NAME (current_class_type)
-		&& IDENTIFIER_TEMPLATE (current_class_name)
-		&& declspecs->type
-		&& declspecs->type == type)
-	      error ("  in instantiation of template %qT",
-		     current_class_type);
-
-	    return error_mark_node;
+	    type = error_mark_node;
+	    decl = NULL_TREE;
 	  }
 	else
 	  {
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 373f883..1573ced 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -835,9 +835,11 @@  grokfield (const cp_declarator *declarator,
     init = NULL_TREE;
 
   value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);
-  if (! value || error_operand_p (value))
+  if (! value || value == error_mark_node)
     /* friend or constructor went bad.  */
     return error_mark_node;
+  if (TREE_TYPE (value) == error_mark_node)
+    return value;
 
   if (TREE_CODE (value) == TYPE_DECL && init)
     {
@@ -1045,8 +1047,10 @@  grokbitfield (const cp_declarator *declarator,
 {
   tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist);
 
-  if (value == error_mark_node) 
+  if (value == error_mark_node)
     return NULL_TREE; /* friends went bad.  */
+  if (TREE_TYPE (value) == error_mark_node)
+    return value;
 
   /* Pass friendly classes back.  */
   if (VOID_TYPE_P (value))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d9a14cc..dcdde00 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8863,9 +8863,8 @@  instantiate_class_template_1 (tree type)
 		  else if (TREE_CODE (r) == FIELD_DECL)
 		    {
 		      /* Determine whether R has a valid type and can be
-			 completed later.  If R is invalid, then it is
-			 replaced by error_mark_node so that it will not be
-			 added to TYPE_FIELDS.  */
+			 completed later.  If R is invalid, then its type is
+			 replaced by error_mark_node.  */
 		      tree rtype = TREE_TYPE (r);
 		      if (can_complete_type_without_circularity (rtype))
 			complete_type (rtype);
@@ -8873,7 +8872,7 @@  instantiate_class_template_1 (tree type)
 		      if (!COMPLETE_TYPE_P (rtype))
 			{
 			  cxx_incomplete_type_error (r, rtype);
-			  r = error_mark_node;
+			  TREE_TYPE (r) = error_mark_node;
 			}
 		    }
 
@@ -10514,8 +10513,6 @@  tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	/* We don't have to set DECL_CONTEXT here; it is set by
 	   finish_member_declaration.  */
 	DECL_CHAIN (r) = NULL_TREE;
-	if (VOID_TYPE_P (type))
-	  error ("instantiation of %q+D as type %qT", r, type);
 
 	apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
 					args, complain, in_decl);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e0ebae9..401904d 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1236,6 +1236,8 @@  process_init_constructor_record (tree type, tree init,
       type = TREE_TYPE (field);
       if (DECL_BIT_FIELD_TYPE (field))
 	type = DECL_BIT_FIELD_TYPE (field);
+      if (type == error_mark_node)
+	return PICFLAG_ERRONEOUS;
 
       if (idx < vec_safe_length (CONSTRUCTOR_ELTS (init)))
 	{
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept15.C b/gcc/testsuite/g++.dg/cpp0x/noexcept15.C
index c735b9e..db5b5c7 100644
--- a/gcc/testsuite/g++.dg/cpp0x/noexcept15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept15.C
@@ -9,11 +9,11 @@  template<class Tp>
     Tp elem;  // { dg-error "incomplete type" }
 
     constexpr single(const Tp& e)
-    : elem(e) { }   // { dg-error "invalid field" }
+    : elem(e) { }
 
     single(single&& s)
     noexcept(std::is_nothrow_move_constructible<Tp>::value) 
-    : elem(s.elem) { } // { dg-error "invalid field|no member" }
+    : elem(s.elem) { }
   };
 
 template<class Tp>
diff --git a/gcc/testsuite/g++.dg/init/array26.C b/gcc/testsuite/g++.dg/init/array26.C
index 83c4e0c..f8f3c37 100644
--- a/gcc/testsuite/g++.dg/init/array26.C
+++ b/gcc/testsuite/g++.dg/init/array26.C
@@ -8,4 +8,4 @@  struct B
   A a; // { dg-error "incomplete type" }
 };
 
-B b[1] = (B[]) { 0 }; // { dg-error "initializer" }
+B b[1] = (B[]) { 0 };
diff --git a/gcc/testsuite/g++.dg/template/error2.C b/gcc/testsuite/g++.dg/template/error2.C
index 96f0bca..be5ab1d 100644
--- a/gcc/testsuite/g++.dg/template/error2.C
+++ b/gcc/testsuite/g++.dg/template/error2.C
@@ -7,9 +7,8 @@ 
 
 template<class T> struct X
 {
-  T m;	// { dg-error "as type 'void'" "void" }
-	// { dg-error "incomplete type" "incomplate" { target *-*-* } 10 }
-	// { dg-error "invalid" "invalid" { target *-*-* } 10 }
+  T m;	// { dg-error "void" "void" }
+	// { dg-error "incomplete type" "incomplete" { target *-*-* } 10 }
 };
 
 template<class T >
diff --git a/gcc/testsuite/g++.dg/template/instantiate3.C b/gcc/testsuite/g++.dg/template/instantiate3.C
index 0e9fd70..c0754da 100644
--- a/gcc/testsuite/g++.dg/template/instantiate3.C
+++ b/gcc/testsuite/g++.dg/template/instantiate3.C
@@ -10,7 +10,7 @@  template <class TYPE>
 struct ACE_Cleanup_Adapter
 {
   TYPE &object ()
-  { return object_; }	// { dg-error "invalid" }
+  { return object_; }
   TYPE object_;		// { dg-error "incomplete type" }
 };