C++ PATCH: PR 27102

Mark Mitchell mark@codesourcery.com
Wed Apr 19 17:01:00 GMT 2006


This patch fixes PR c++/27102.  

Unfortunately, this turned out to be more complex than I had hoped;
fortunately, that lead to some other cleanups.  In particular, the
parser was creating a cdk_error declarator for the name of an abstract
declarator; the natural representation is of course a NULL
declarator.

Tested on x86_64-unknown-linux-gnu, applied to mainline.  Because the
patch seems unnecessarily large, I'm not going to try to backport it
to 4.1 until it's had time to settle in on mainline.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-04-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/27102
	* class.c (currently_open_class): Tidy.
	* decl.c (grokdeclarator): If we encounter an erroneous
	declarator, assume that we have already issued an error message
	and return.  Return error_mark_node instead of NULL_TREE in more
	places.  Issue errors about function definitions that do not have
	a function declarator.  Check for complete types for all function
	definitions. 
	* cp-tree.h (cp_error_declarator): Remove.
	(currently_open_class): Change return type.
	* parser.c (cp_parser_id_expression): Add optional_p parameter.
	(cp_parser_parse_diagnose_invalid_type_name): Adjust calls.
	(cp_parser_id_expression): Likewise.
	(cp_parser_unqualified_id): If the name is optional, return
	NULL_TREE.
	(cp_parser_postfix_dot_deref_expression): Adjust calls.
	(cp_parser_type_parameter): Likewise.
	(cp_parser_unqualified_id): Likewise.
	(cp_parser_direct_declarator): Likewise.
	(cp_parser_declarator_id): Add optional_p parameter.
	(cp_parser_function_definition_from_specifiers_and_declarator):
	Assume that start_function indicates failure only if it has issued
	an error.
	(cp_parser_omp_var_list_no_open): Adjust calls.
	
2006-04-19  Mark Mitchell  <mark@codesourcery.com>

	PR c++/27102
	* g++.dg/template/crash35.C: Tweak error markers.
	* g++.dg/template/crash46.C: New test.
	* g++.old-deja/g++.brendan/friend4.C: Tweak error markers.
	* g++.old-deja/g++.pt/incomplete1.C: Likewise.

Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 112985)
+++ gcc/cp/class.c	(working copy)
@@ -5494,25 +5494,33 @@ pop_class_stack (void)
     --current_class_stack[current_class_depth - 1].hidden;
 }
 
-/* Returns 1 if current_class_type is either T or a nested type of T.
-   We start looking from 1 because entry 0 is from global scope, and has
-   no type.  */
+/* Returns 1 if the class type currently being defined is either T or
+   a nested type of T.  */
 
-int
+bool
 currently_open_class (tree t)
 {
   int i;
-  if (current_class_type && same_type_p (t, current_class_type))
-    return 1;
-  for (i = current_class_depth - 1; i > 0; --i)
-    {
-      if (current_class_stack[i].hidden)
-	break;
-      if (current_class_stack[i].type
-	  && same_type_p (current_class_stack [i].type, t))
-	return 1;
+
+  /* We start looking from 1 because entry 0 is from global scope,
+     and has no type.  */
+  for (i = current_class_depth; i > 0; --i)
+    {
+      tree c;
+      if (i == current_class_depth)
+	c = current_class_type;
+      else
+	{
+	  if (current_class_stack[i].hidden)
+	    break;
+	  c = current_class_stack[i].type;
+	}
+      if (!c)
+	continue;
+      if (same_type_p (c, t))
+	return true;
     }
-  return 0;
+  return false;
 }
 
 /* If either current_class_type or one of its enclosing classes are derived
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 112985)
+++ gcc/cp/decl.c	(working copy)
@@ -6956,7 +6956,7 @@ grokdeclarator (const cp_declarator *dec
 	    break;
 
 	  case cdk_error:
-	    break;
+	    return error_mark_node;
 
 	  default:
 	    gcc_unreachable ();
@@ -6966,11 +6966,15 @@ grokdeclarator (const cp_declarator *dec
 	break;
     }
 
-  /* A function definition's declarator must have the form of
-     a function declarator.  */
-
+  /* [dcl.fct.edf]
+     
+     The declarator in a function-definition shall have the form
+     D1 ( parameter-declaration-clause) ...  */
   if (funcdef_flag && innermost_code != cdk_function)
-    return NULL_TREE;
+    {
+      error ("function definition does not declare parameters");
+      return error_mark_node;
+    }
 
   if (((dname && IDENTIFIER_OPNAME_P (dname)) || flags == TYPENAME_FLAG)
       && innermost_code != cdk_function
@@ -7711,6 +7715,20 @@ grokdeclarator (const cp_declarator *dec
 	    pedwarn ("extra qualification %<%T::%> on member %qs",
 		     ctype, name);
 	}
+      else if (/* If the qualifying type is already complete, then we
+		  can skip the following checks.  */
+	       !COMPLETE_TYPE_P (ctype)
+	       /* If a function is being defined, then the qualifing
+		  type must be complete.  The qualifing type may be
+		  incomplete for a declaration only if the qualitying
+		  type is one of the classes presently being defined,
+		  or if it is a dependent type.  */
+	       && (funcdef_flag 
+		   || !(dependent_type_p (ctype)
+			|| currently_open_class (ctype)))
+	       /* Check that the qualifing type is complete.  */
+	       && !complete_type_or_else (ctype, NULL_TREE))
+	return error_mark_node;
       else if (TREE_CODE (type) == FUNCTION_TYPE)
 	{
 	  tree sname = declarator->u.id.unqualified_name;
@@ -7736,23 +7754,10 @@ grokdeclarator (const cp_declarator *dec
 					       TYPE_ARG_TYPES (type));
 	}
       else if (declspecs->specs[(int)ds_typedef]
-	       || COMPLETE_TYPE_P (complete_type (ctype)))
-	{
-	  /* Have to move this code elsewhere in this function.
-	     this code is used for i.e., typedef int A::M; M *pm;
-
-	     It is?  How? jason 10/2/94 */
-
-	  if (current_class_type)
-	    {
-	      error ("cannot declare member %<%T::%s%> within %qT",
-		     ctype, name, current_class_type);
-	      return void_type_node;
-	    }
-	}
-      else
+	       && current_class_type)
 	{
-	  cxx_incomplete_type_error (NULL_TREE, ctype);
+	  error ("cannot declare member %<%T::%s%> within %qT",
+		 ctype, name, current_class_type);
 	  return error_mark_node;
 	}
     }
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 112985)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -3691,9 +3691,6 @@ struct cp_declarator {
   } u;
 };
 
-/* An erroneous declarator.  */
-extern cp_declarator *cp_error_declarator;
-
 /* A parameter list indicating for a function with no parameters,
    e.g  "int f(void)".  */
 extern cp_parameter_declarator *no_parameters;
@@ -3750,7 +3747,7 @@ extern tree get_vtable_decl			(tree, int
 extern void resort_type_method_vec		(void *, void *,
 						 gt_pointer_operator, void *);
 extern bool add_method				(tree, tree, tree);
-extern int currently_open_class			(tree);
+extern bool currently_open_class		(tree);
 extern tree currently_open_derived_class	(tree);
 extern tree finish_struct			(tree, tree);
 extern void finish_struct_1			(tree);
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 112985)
+++ gcc/cp/parser.c	(working copy)
@@ -780,7 +780,8 @@ static cp_parameter_declarator *make_par
 static cp_declarator *make_ptrmem_declarator
   (cp_cv_quals, tree, cp_declarator *);
 
-cp_declarator *cp_error_declarator;
+/* An erroneous declarator.  */
+static cp_declarator *cp_error_declarator;
 
 /* The obstack on which declarators and related data structures are
    allocated.  */
@@ -1389,9 +1390,9 @@ static bool cp_parser_translation_unit
 static tree cp_parser_primary_expression
   (cp_parser *, bool, bool, bool, cp_id_kind *);
 static tree cp_parser_id_expression
-  (cp_parser *, bool, bool, bool *, bool);
+  (cp_parser *, bool, bool, bool *, bool, bool);
 static tree cp_parser_unqualified_id
-  (cp_parser *, bool, bool, bool);
+  (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_nested_name_specifier_opt
   (cp_parser *, bool, bool, bool, bool);
 static tree cp_parser_nested_name_specifier
@@ -1536,7 +1537,7 @@ static enum tree_code cp_parser_ptr_oper
 static cp_cv_quals cp_parser_cv_qualifier_seq_opt
   (cp_parser *);
 static tree cp_parser_declarator_id
-  (cp_parser *);
+  (cp_parser *, bool);
 static tree cp_parser_type_id
   (cp_parser *);
 static void cp_parser_type_specifier_seq
@@ -2142,7 +2143,8 @@ cp_parser_parse_and_diagnose_invalid_typ
 				/*template_keyword_p=*/false,
 				/*check_dependency_p=*/true,
 				/*template_p=*/NULL,
-				/*declarator_p=*/true);
+				/*declarator_p=*/true,
+				/*optional_p=*/false);
   /* After the id-expression, there should be a plain identifier,
      otherwise this is not a simple variable declaration. Also, if
      the scope is dependent, we cannot do much.  */
@@ -3021,7 +3023,8 @@ cp_parser_primary_expression (cp_parser 
 				     /*template_keyword_p=*/false,
 				     /*check_dependency_p=*/true,
 				     &template_p,
-				     /*declarator_p=*/false);
+				     /*declarator_p=*/false,
+				     /*optional_p=*/false);
 	if (id_expression == error_mark_node)
 	  return error_mark_node;
 	token = cp_lexer_peek_token (parser->lexer);
@@ -3154,7 +3157,8 @@ cp_parser_id_expression (cp_parser *pars
 			 bool template_keyword_p,
 			 bool check_dependency_p,
 			 bool *template_p,
-			 bool declarator_p)
+			 bool declarator_p,
+			 bool optional_p)
 {
   bool global_scope_p;
   bool nested_name_specifier_p;
@@ -3197,7 +3201,8 @@ cp_parser_id_expression (cp_parser *pars
       /* Process the final unqualified-id.  */
       unqualified_id = cp_parser_unqualified_id (parser, *template_p,
 						 check_dependency_p,
-						 declarator_p);
+						 declarator_p,
+						 /*optional_p=*/false);
       /* Restore the SAVED_SCOPE for our caller.  */
       parser->scope = saved_scope;
       parser->object_scope = saved_object_scope;
@@ -3255,7 +3260,8 @@ cp_parser_id_expression (cp_parser *pars
   else
     return cp_parser_unqualified_id (parser, template_keyword_p,
 				     /*check_dependency_p=*/true,
-				     declarator_p);
+				     declarator_p,
+				     optional_p);
 }
 
 /* Parse an unqualified-id.
@@ -3284,7 +3290,8 @@ static tree
 cp_parser_unqualified_id (cp_parser* parser,
 			  bool template_keyword_p,
 			  bool check_dependency_p,
-			  bool declarator_p)
+			  bool declarator_p, 
+			  bool optional_p)
 {
   cp_token *token;
 
@@ -3505,6 +3512,8 @@ cp_parser_unqualified_id (cp_parser* par
       /* Fall through.  */
 
     default:
+      if (optional_p)
+	return NULL_TREE;
       cp_parser_error (parser, "expected unqualified-id");
       return error_mark_node;
     }
@@ -4501,7 +4510,8 @@ cp_parser_postfix_dot_deref_expression (
 	       cp_parser_optional_template_keyword (parser),
 	       /*check_dependency_p=*/true,
 	       &template_p,
-	       /*declarator_p=*/false));
+	       /*declarator_p=*/false,
+	       /*optional_p=*/false));
       /* In general, build a SCOPE_REF if the member name is qualified.
 	 However, if the name was not dependent and has already been
 	 resolved; there is no need to build the SCOPE_REF.  For example;
@@ -8623,7 +8633,8 @@ cp_parser_type_parameter (cp_parser* par
 					 /*template_keyword_p=*/false,
 					 /*check_dependency_p=*/true,
 					 /*template_p=*/&is_template,
-					 /*declarator_p=*/false);
+					 /*declarator_p=*/false,
+					 /*optional_p=*/false);
 	    if (TREE_CODE (default_argument) == TYPE_DECL)
 	      /* If the id-expression was a template-id that refers to
 		 a template-class, we already have the declaration here,
@@ -9177,7 +9188,8 @@ cp_parser_template_argument (cp_parser* 
 				      /*template_keyword_p=*/false,
 				      /*check_dependency_p=*/true,
 				      &template_p,
-				      /*declarator_p=*/false);
+				      /*declarator_p=*/false,
+				      /*optional_p=*/false);
   /* If the next token isn't a `,' or a `>', then this argument wasn't
      really finished.  */
   if (!cp_parser_next_token_ends_template_argument_p (parser))
@@ -10624,7 +10636,8 @@ cp_parser_using_declaration (cp_parser* 
   identifier = cp_parser_unqualified_id (parser,
 					 /*template_keyword_p=*/false,
 					 /*check_dependency_p=*/true,
-					 /*declarator_p=*/true);
+					 /*declarator_p=*/true,
+					 /*optional_p=*/false);
 
   /* The function we call to handle a using-declaration is different
      depending on what scope we are in.  */
@@ -11515,25 +11528,31 @@ cp_parser_direct_declarator (cp_parser* 
 	  tree qualifying_scope;
 	  tree unqualified_name;
 	  special_function_kind sfk;
+	  bool abstract_ok;
 
 	  /* Parse a declarator-id */
-	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
+	  abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
+	  if (abstract_ok)
 	    cp_parser_parse_tentatively (parser);
-	  unqualified_name = cp_parser_declarator_id (parser);
+	  unqualified_name 
+	    = cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
 	  qualifying_scope = parser->scope;
-	  if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
+	  if (abstract_ok)
 	    {
 	      if (!cp_parser_parse_definitely (parser))
 		unqualified_name = error_mark_node;
-	      else if (qualifying_scope
-		       || (TREE_CODE (unqualified_name)
-			   != IDENTIFIER_NODE))
+	      else if (unqualified_name
+		       && (qualifying_scope
+			   || (TREE_CODE (unqualified_name)
+			       != IDENTIFIER_NODE)))
 		{
 		  cp_parser_error (parser, "expected unqualified-id");
 		  unqualified_name = error_mark_node;
 		}
 	    }
 
+	  if (!unqualified_name)
+	    return NULL;
 	  if (unqualified_name == error_mark_node)
 	    {
 	      declarator = cp_error_declarator;
@@ -11853,7 +11872,7 @@ cp_parser_cv_qualifier_seq_opt (cp_parse
    unqualified-id.  */
 
 static tree
-cp_parser_declarator_id (cp_parser* parser)
+cp_parser_declarator_id (cp_parser* parser, bool optional_p)
 {
   tree id;
   /* The expression must be an id-expression.  Assume that qualified
@@ -11874,8 +11893,9 @@ cp_parser_declarator_id (cp_parser* pars
 				/*template_keyword_p=*/false,
 				/*check_dependency_p=*/false,
 				/*template_p=*/NULL,
-				/*declarator_p=*/true);
-  if (BASELINK_P (id))
+				/*declarator_p=*/true,
+				optional_p);
+  if (id && BASELINK_P (id))
     id = BASELINK_FUNCTIONS (id);
   return id;
 }
@@ -15298,7 +15318,6 @@ cp_parser_function_definition_from_speci
   if (!success_p)
     {
       /* Skip the entire function.  */
-      error ("invalid function declaration");
       cp_parser_skip_to_end_of_block_or_statement (parser);
       fn = error_mark_node;
     }
@@ -17786,7 +17805,8 @@ cp_parser_omp_var_list_no_open (cp_parse
       name = cp_parser_id_expression (parser, /*template_p=*/false,
 				      /*check_dependency_p=*/true,
 				      /*template_p=*/NULL,
-				      /*declarator_p=*/false);
+				      /*declarator_p=*/false,
+				      /*optional_p=*/false);
       if (name == error_mark_node)
 	goto skip_comma;
 
Index: gcc/testsuite/g++.dg/template/crash35.C
===================================================================
--- gcc/testsuite/g++.dg/template/crash35.C	(revision 112985)
+++ gcc/testsuite/g++.dg/template/crash35.C	(working copy)
@@ -5,5 +5,5 @@ template <typename T> struct C; // { dg-
 
 template <typename T> void C<T>::f() // { dg-error "invalid|template" }
 {
-  const foo bar; // { dg-error "name a type" }
+  const foo bar;
 }
Index: gcc/testsuite/g++.dg/template/crash46.C
===================================================================
--- gcc/testsuite/g++.dg/template/crash46.C	(revision 0)
+++ gcc/testsuite/g++.dg/template/crash46.C	(revision 0)
@@ -0,0 +1,5 @@
+// PR c++/27102
+
+template <class T>
+void T::foo() {} // { dg-error "invalid" }
+
Index: gcc/testsuite/g++.old-deja/g++.brendan/friend4.C
===================================================================
--- gcc/testsuite/g++.old-deja/g++.brendan/friend4.C	(revision 112985)
+++ gcc/testsuite/g++.old-deja/g++.brendan/friend4.C	(working copy)
@@ -2,5 +2,5 @@
 // GROUPS passed friends
 // do_friend should complain that foo was declared as a friend of
 // A before A was defined
-struct A;
+struct A; // { dg-error "forward" } 
 struct B { friend A::foo (); };// { dg-error "" } .*
Index: gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C
===================================================================
--- gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C	(revision 112985)
+++ gcc/testsuite/g++.old-deja/g++.pt/incomplete1.C	(working copy)
@@ -6,6 +6,6 @@
 // Inspired by by 756. We'd ICE when trying to define a member of an
 // incomplete template type.
 
-template<class X> struct ObjCount;  // { dg-error "" } forward decl
+template<class X> struct ObjCount;
 
 template<class X> int ObjCount<X>::m; // { dg-error "" } undefined type



More information about the Gcc-patches mailing list