C++ PATCH: PR 25635, 25638, 25638, 25633, 25634

Mark Mitchell mark@codesourcery.com
Tue Jan 3 08:46:00 GMT 2006


This patch fixes various C++ regressions:

* 25635: We failed to set TYPE_HAS_CONVERSION on a type for which a
  (erroneous) conversion operator declaration appeared after the type
  was complete.  As a result, subsequent attempts to find the
  conversion operator failed, leading to an error cases.

* 25638: We created multiple destructor declarations for a class, in
  the presence of an (erroneous) friend destructor declaration.  Other
  parts of the front end reasonably assume that a class has only one
  destructor.  Fixed by refusing to register multiple destructors.

* 25637: We permitted friend function definitions of members of other
  classes; friend declarations should be allowed, but not
  definitions.

* 25633: We failed to discard erroneous mem-initializers.

* 25634: We failed to check for the presence of too many template
  parameter lists in elaborated type specifiers.

Tested on x86_64-unknown-linux-gnu.  Applied on the mainline, 4.1, and
4.0 branches; the branch versions omit the cleanups below which are
not necessary to fix the bugs.

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

2006-01-02  Mark Mitchell  <mark@codesourcery.com>

	PR c++/25635
	* class.c (add_method): Set TYPE_HAS_CONVERSION for classes with a
	conversion operator.
	* decl.c (grokdeclarator): Do not set TYPE_HAS_CONVERSION here.

	PR c++/25638
	* class.c (add_method): Never associate more than one destructor
	with a single class.

	PR c++/25637
	* cp-tree.h (do_friend): Adjust prototype.
	* decl.c (grokfndecl): Make funcdef_flag a bool, not an int.
	(grokdeclarator): Likewise.  Refine check for invalid
	declarations/definitions of member functions outside of their own
	class.
	* friend.c (do_friend): Make funcdef_flag a bool, not an int.

	PR c++/25633
	* parser.c (cp_parser_mem_initializer_list): Check result of
	cp_parser_mem_initializer against error_mark_node, not NULL_TREE.
	(cp_parser_mem_initializer): Return error_mark_node for failure.

	PR c++/25634
	* parser.c (cp_parser_template_parameter_list): Call
	begin_template_parm_list and end_template_parm_list here.
	(cp_parser_type_parameter): Not here.
	(cp_parser_template_declaration_after_export): Or here.
	(cp_parser_elaborated_type_specifier): Call
	cp_parser_check_template_parameters.

	* tree.c (build_target_expr_with_type): Use force_target_expr.

2006-01-02  Mark Mitchell  <mark@codesourcery.com>

	PR c++/25635
	* g++.dg/parse/operator6.C: New test.

	PR c++/25637
	* g++.dg/parse/error29.C: New test.

	PR c++/25638
	* g++.dg/parse/dtor6.C: New test.

	PR c++/25633
	* g++.dg/parse/ctor3.C: New test.

	PR c++/25634
	* g++.dg/template/class3.C: New test.

Index: gcc/testsuite/g++.dg/parse/operator6.C
===================================================================
--- gcc/testsuite/g++.dg/parse/operator6.C	(revision 0)
+++ gcc/testsuite/g++.dg/parse/operator6.C	(revision 0)
@@ -0,0 +1,5 @@
+// PR c++/25635
+
+struct A {};
+
+A::operator int(); // { dg-error "class" }
Index: gcc/testsuite/g++.dg/parse/error29.C
===================================================================
--- gcc/testsuite/g++.dg/parse/error29.C	(revision 0)
+++ gcc/testsuite/g++.dg/parse/error29.C	(revision 0)
@@ -0,0 +1,12 @@
+// PR c++/25637
+
+struct A { 
+  void foo();
+  A(); 
+  void operator delete(void *);
+};
+struct B { 
+  friend void A::foo() {} // { dg-error "define" }
+  friend void A::operator delete(void*) {} // { dg-error "define" }
+  friend A::A() {} // { dg-error "define" }
+};
Index: gcc/testsuite/g++.dg/parse/dtor6.C
===================================================================
--- gcc/testsuite/g++.dg/parse/dtor6.C	(revision 0)
+++ gcc/testsuite/g++.dg/parse/dtor6.C	(revision 0)
@@ -0,0 +1,8 @@
+// PR c++/25638
+
+struct A { ~A(); }; // { dg-error "candidate" }  
+
+struct B : A
+{
+  template<int> friend A::~A(); // { dg-error "match" }
+};
Index: gcc/testsuite/g++.dg/parse/ctor3.C
===================================================================
--- gcc/testsuite/g++.dg/parse/ctor3.C	(revision 0)
+++ gcc/testsuite/g++.dg/parse/ctor3.C	(revision 0)
@@ -0,0 +1,8 @@
+// PR c++/25633
+
+struct A {};
+
+struct B : A
+{
+  B() : A {} // { dg-error "expected" }
+};
Index: gcc/testsuite/g++.dg/template/class3.C
===================================================================
--- gcc/testsuite/g++.dg/template/class3.C	(revision 0)
+++ gcc/testsuite/g++.dg/template/class3.C	(revision 0)
@@ -0,0 +1,2 @@
+// PR c++/25634
+template<int> template<int> struct A; // { dg-error "too many" }
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 109259)
+++ gcc/cp/class.c	(working copy)
@@ -1059,10 +1059,16 @@ add_method (tree type, tree method, tree
 	}
     }
 
+  /* A class should never have more than one destructor.  */ 
+  if (current_fns && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method))
+    return false;
+
   /* Add the new binding.  */
   overload = build_overload (method, current_fns);
 
-  if (!conv_p && slot >= CLASSTYPE_FIRST_CONVERSION_SLOT && !complete_p)
+  if (conv_p)
+    TYPE_HAS_CONVERSION (type) = 1;
+  else if (slot >= CLASSTYPE_FIRST_CONVERSION_SLOT && !complete_p)
     push_class_level_binding (DECL_NAME (method), overload);
 
   if (insert_p)
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 109259)
+++ gcc/cp/decl.c	(working copy)
@@ -5697,7 +5697,7 @@ grokfndecl (tree ctype,
 	    int publicp,
 	    int inlinep,
 	    special_function_kind sfk,
-	    int funcdef_flag,
+	    bool funcdef_flag,
 	    int template_count,
 	    tree in_namespace,
 	    tree* attrlist)
@@ -5918,7 +5918,7 @@ grokfndecl (tree ctype,
 
   decl = check_explicit_specialization (orig_declarator, decl,
 					template_count,
-					2 * (funcdef_flag != 0) +
+					2 * funcdef_flag +
 					4 * (friendp != 0));
   if (decl == error_mark_node)
     return NULL_TREE;
@@ -5940,27 +5940,26 @@ grokfndecl (tree ctype,
 				 > template_class_depth (ctype))
 				? current_template_parms
 				: NULL_TREE);
-
-      if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
-	/* Because grokfndecl is always supposed to return a
-	   FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
-	   here.  We depend on our callers to figure out that its
-	   really a template that's being returned.  */
-	old_decl = DECL_TEMPLATE_RESULT (old_decl);
-
-      if (old_decl && DECL_STATIC_FUNCTION_P (old_decl)
-	  && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-	/* Remove the `this' parm added by grokclassfn.
-	   XXX Isn't this done in start_function, too?  */
-	revert_static_member_fn (decl);
-      if (old_decl && DECL_ARTIFICIAL (old_decl))
-	error ("definition of implicitly-declared %qD", old_decl);
-
       if (old_decl)
 	{
 	  tree ok;
 	  tree pushed_scope;
 
+	  if (TREE_CODE (old_decl) == TEMPLATE_DECL)
+	    /* Because grokfndecl is always supposed to return a
+	       FUNCTION_DECL, we pull out the DECL_TEMPLATE_RESULT
+	       here.  We depend on our callers to figure out that its
+	       really a template that's being returned.  */
+	    old_decl = DECL_TEMPLATE_RESULT (old_decl);
+
+	  if (DECL_STATIC_FUNCTION_P (old_decl)
+	      && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+	    /* Remove the `this' parm added by grokclassfn.
+	       XXX Isn't this done in start_function, too?  */
+	    revert_static_member_fn (decl);
+	  if (DECL_ARTIFICIAL (old_decl))
+	    error ("definition of implicitly-declared %qD", old_decl);
+
 	  /* Since we've smashed OLD_DECL to its
 	     DECL_TEMPLATE_RESULT, we must do the same to DECL.  */
 	  if (TREE_CODE (decl) == TEMPLATE_DECL)
@@ -6627,7 +6626,8 @@ grokdeclarator (const cp_declarator *dec
   tree typedef_decl = NULL_TREE;
   const char *name = NULL;
   tree typedef_type = NULL_TREE;
-  int funcdef_flag = 0;
+  /* True if this declarator is a function definition.  */
+  bool funcdef_flag = false;
   cp_declarator_kind innermost_code = cdk_error;
   int bitfield = 0;
 #if 0
@@ -6674,9 +6674,9 @@ grokdeclarator (const cp_declarator *dec
   thread_p = declspecs->specs[(int)ds_thread];
 
   if (decl_context == FUNCDEF)
-    funcdef_flag = 1, decl_context = NORMAL;
+    funcdef_flag = true, decl_context = NORMAL;
   else if (decl_context == MEMFUNCDEF)
-    funcdef_flag = -1, decl_context = FIELD;
+    funcdef_flag = true, decl_context = FIELD;
   else if (decl_context == BITFIELD)
     bitfield = 1, decl_context = FIELD;
 
@@ -7349,8 +7349,6 @@ grokdeclarator (const cp_declarator *dec
 		&& (friendp == 0 || dname == current_class_name))
 	      ctype = current_class_type;
 
-	    if (ctype && sfk == sfk_conversion)
-	      TYPE_HAS_CONVERSION (ctype) = 1;
 	    if (ctype && (sfk == sfk_constructor
 			  || sfk == sfk_destructor))
 	      {
@@ -7604,22 +7602,25 @@ grokdeclarator (const cp_declarator *dec
 	{
 	  tree sname = declarator->u.id.unqualified_name;
 
+	  if (current_class_type
+	      && (!friendp || funcdef_flag))
+	    {
+	      error (funcdef_flag
+		     ? "cannot define member function %<%T::%s%> within %<%T%>"
+		     : "cannot declare member function %<%T::%s%> within %<%T%>",
+		     ctype, name, current_class_type);
+	      return error_mark_node;
+	    }
+
 	  if (TREE_CODE (sname) == IDENTIFIER_NODE
 	      && NEW_DELETE_OPNAME_P (sname))
 	    /* Overloaded operator new and operator delete
 	       are always static functions.  */
 	    ;
-	  else if (current_class_type == NULL_TREE || friendp)
-	    type
-	      = build_method_type_directly (ctype,
-					    TREE_TYPE (type),
-					    TYPE_ARG_TYPES (type));
 	  else
-	    {
-	      error ("cannot declare member function %<%T::%s%> within %<%T%>",
-		     ctype, name, current_class_type);
-	      return error_mark_node;
-	    }
+	    type = build_method_type_directly (ctype,
+					       TREE_TYPE (type),
+					       TYPE_ARG_TYPES (type));
 	}
       else if (declspecs->specs[(int)ds_typedef]
 	       || COMPLETE_TYPE_P (complete_type (ctype)))
@@ -8179,7 +8180,7 @@ grokdeclarator (const cp_declarator *dec
 		  {
 		    decl = check_explicit_specialization
 		      (unqualified_id, decl, template_count,
-		       2 * (funcdef_flag != 0) + 4);
+		       2 * funcdef_flag + 4);
 		    if (decl == error_mark_node)
 		      return error_mark_node;
 		  }
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 109259)
+++ gcc/cp/tree.c	(working copy)
@@ -325,8 +325,6 @@ build_cplus_new (tree type, tree init)
 tree
 build_target_expr_with_type (tree init, tree type)
 {
-  tree slot;
-
   gcc_assert (!VOID_TYPE_P (type));
 
   if (TREE_CODE (init) == TARGET_EXPR)
@@ -342,8 +340,7 @@ build_target_expr_with_type (tree init, 
        aggregate; there's no additional work to be done.  */
     return force_rvalue (init);
 
-  slot = build_local_temp (type);
-  return build_target_expr (slot, init);
+  return force_target_expr (type, init);
 }
 
 /* Like the above function, but without the checking.  This function should
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 109259)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -3935,7 +3935,7 @@ extern tree cplus_expand_constant		(tree
 extern int is_friend				(tree, tree);
 extern void make_friend_class			(tree, tree, bool);
 extern void add_friend				(tree, tree, bool);
-extern tree do_friend				(tree, tree, tree, tree, enum overload_flags, cp_cv_quals, int);
+extern tree do_friend				(tree, tree, tree, tree, enum overload_flags, cp_cv_quals, bool);
 
 /* in init.c */
 extern tree expand_member_init			(tree);
Index: gcc/cp/friend.c
===================================================================
--- gcc/cp/friend.c	(revision 109259)
+++ gcc/cp/friend.c	(working copy)
@@ -408,7 +408,7 @@ tree
 do_friend (tree ctype, tree declarator, tree decl,
 	   tree attrlist, enum overload_flags flags,
 	   cp_cv_quals quals,
-	   int funcdef_flag)
+	   bool funcdef_flag)
 {
   /* Every decl that gets here is a friend of something.  */
   DECL_FRIEND_P (decl) = 1;
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 109259)
+++ gcc/cp/parser.c	(working copy)
@@ -7808,7 +7808,7 @@ cp_parser_mem_initializer_list (cp_parse
       /* Parse the mem-initializer.  */
       mem_initializer = cp_parser_mem_initializer (parser);
       /* Add it to the list, unless it was erroneous.  */
-      if (mem_initializer)
+      if (mem_initializer != error_mark_node)
 	{
 	  TREE_CHAIN (mem_initializer) = mem_initializer_list;
 	  mem_initializer_list = mem_initializer;
@@ -7837,7 +7837,8 @@ cp_parser_mem_initializer_list (cp_parse
 
    Returns a TREE_LIST.  The TREE_PURPOSE is the TYPE (for a base
    class) or FIELD_DECL (for a non-static data member) to initialize;
-   the TREE_VALUE is the expression-list.  */
+   the TREE_VALUE is the expression-list.  An empty initialization
+   list is represented by void_list_node.  */
 
 static tree
 cp_parser_mem_initializer (cp_parser* parser)
@@ -7862,12 +7863,14 @@ cp_parser_mem_initializer (cp_parser* pa
     = cp_parser_parenthesized_expression_list (parser, false,
 					       /*cast_p=*/false,
 					       /*non_constant_p=*/NULL);
+  if (expression_list == error_mark_node)
+    return error_mark_node;
   if (!expression_list)
     expression_list = void_type_node;
 
   in_base_initializer = 0;
 
-  return member ? build_tree_list (member, expression_list) : NULL_TREE;
+  return member ? build_tree_list (member, expression_list) : error_mark_node;
 }
 
 /* Parse a mem-initializer-id.
@@ -8277,6 +8280,7 @@ cp_parser_template_parameter_list (cp_pa
 {
   tree parameter_list = NULL_TREE;
 
+  begin_template_parm_list ();
   while (true)
     {
       tree parameter;
@@ -8299,7 +8303,7 @@ cp_parser_template_parameter_list (cp_pa
       cp_lexer_consume_token (parser->lexer);
     }
 
-  return parameter_list;
+  return end_template_parm_list (parameter_list);
 }
 
 /* Parse a template-parameter.
@@ -8447,10 +8451,7 @@ cp_parser_type_parameter (cp_parser* par
 	/* Look for the `<'.  */
 	cp_parser_require (parser, CPP_LESS, "`<'");
 	/* Parse the template-parameter-list.  */
-	begin_template_parm_list ();
-	parameter_list
-	  = cp_parser_template_parameter_list (parser);
-	parameter_list = end_template_parm_list (parameter_list);
+	parameter_list = cp_parser_template_parameter_list (parser);
 	/* Look for the `>'.  */
 	cp_parser_require (parser, CPP_GREATER, "`>'");
 	/* Look for the `class' keyword.  */
@@ -10112,6 +10113,11 @@ cp_parser_elaborated_type_specifier (cp_
 	    (parser->num_template_parameter_lists
 	     && (cp_parser_next_token_starts_class_definition_p (parser)
 		 || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
+	  /* An unqualified name was used to reference this type, so
+	     there were no qualifying templates.  */
+	  if (!cp_parser_check_template_parameters (parser, 
+						    /*num_templates=*/0))
+	    return error_mark_node;
 	  type = xref_tag (tag_type, identifier, ts, template_p);
 	}
     }
@@ -15259,12 +15265,8 @@ cp_parser_template_declaration_after_exp
       parameter_list = NULL_TREE;
     }
   else
-    {
-      /* Parse the template parameters.  */
-      begin_template_parm_list ();
-      parameter_list = cp_parser_template_parameter_list (parser);
-      parameter_list = end_template_parm_list (parameter_list);
-    }
+    /* Parse the template parameters.  */
+    parameter_list = cp_parser_template_parameter_list (parser);
 
   /* Look for the `>'.  */
   cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");



More information about the Gcc-patches mailing list