[C++ Patch] PR 19200

Paolo Carlini paolo.carlini@oracle.com
Mon Jun 9 23:05:00 GMT 2014


Hi,

another old issue, which should be also relatively easy to fix. The 
problem is clear, for:

struct S {
   struct T{};
   friend void S(T);
};

cp_parser_direct_declarator sees a name which matches that of a kosher 
constructor and sets sfk_constructor. Then things go quickly wrong 
because a constructor cannot have a return type specification, thus 
check_special_function_return_type, called by grokdeclarator, complains.

I tried various ideas (eg, I'm also attaching an alternate approach 
passing down the friend information from cp_parser_member_declaration to 
cp_parser_direct_declarator), but, all in all, I propose to adjust 
things in grodeclarator itself. Tested x86_64-linux.

Thanks!
Paolo.

//////////////////////////
-------------- next part --------------
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 211389)
+++ cp/decl.c	(working copy)
@@ -8774,7 +8774,8 @@ grokdeclarator (const cp_declarator *declarator,
   tree type = NULL_TREE;
   int longlong = 0;
   int explicit_int128 = 0;
-  int virtualp, explicitp, friendp, inlinep, staticp;
+  int virtualp, explicitp, inlinep, staticp;
+  int friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
   int explicit_int = 0;
   int explicit_char = 0;
   int defaulted_int = 0;
@@ -8880,6 +8881,26 @@ grokdeclarator (const cp_declarator *declarator,
 	      sfk = id_declarator->declarator->u.id.sfk;
 	      if (sfk == sfk_destructor)
 		flags = DTOR_FLAG;
+	      else if (sfk == sfk_constructor
+		       && friendp
+		       && declspecs->type)
+		/* cp_parser_direct_declarator doesn't know about the
+		   'friend' specifier and returns sfk_constructor for
+
+		   struct S {
+		     struct T{};
+		     friend void S(T);
+		   };
+
+		   thus adjust it here (c++/19200).  Note: the return
+		   type is checked because with -fpermissive we still
+		   want to accept
+
+		   struct S {
+		     struct T{};
+		     friend S::S(T);
+		   };  */
+		sfk = sfk_none;
 	    }
 	  break;
 
@@ -9378,7 +9399,6 @@ grokdeclarator (const cp_declarator *declarator,
       storage_class = sc_none;
       staticp = 0;
     }
-  friendp = decl_spec_seq_has_spec_p (declspecs, ds_friend);
 
   /* Issue errors about use of storage classes for parameters.  */
   if (decl_context == PARM)
Index: testsuite/g++.dg/parse/friend7.C
===================================================================
--- testsuite/g++.dg/parse/friend7.C	(revision 211384)
+++ testsuite/g++.dg/parse/friend7.C	(working copy)
@@ -17,16 +17,16 @@ struct B
 
 struct C
 {
-  friend int C ();		// { dg-error "return type|in friend decl" }
+  friend int C ();
   friend int ~C ();		// { dg-error "return type|in friend decl" }
-  friend int C (const C &);	// { dg-error "return type|in friend decl" }
+  friend int C (const C &);
 };
 
 struct D
 {
-  friend int D () {}		// { dg-error "return type|in friend decl" }
+  friend int D () {}
   friend int ~D () {}		// { dg-error "return type|in friend decl" }
-  friend int D (const D &) {}	// { dg-error "return type|in friend decl" }
+  friend int D (const D &) {}
 };
 
 struct E
Index: testsuite/g++.dg/parse/friend9.C
===================================================================
--- testsuite/g++.dg/parse/friend9.C	(revision 0)
+++ testsuite/g++.dg/parse/friend9.C	(working copy)
@@ -0,0 +1,6 @@
+// PR c++/19200
+
+struct S {
+  struct T{};
+  friend void S(T);
+};
-------------- next part --------------
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 211384)
+++ cp/parser.c	(working copy)
@@ -2078,9 +2078,9 @@ static tree cp_parser_decltype
 static tree cp_parser_init_declarator
   (cp_parser *, cp_decl_specifier_seq *, vec<deferred_access_check, va_gc> *, bool, bool, int, bool *, tree *);
 static cp_declarator *cp_parser_declarator
-  (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
+  (cp_parser *, cp_parser_declarator_kind, int *, bool *, bool, bool);
 static cp_declarator *cp_parser_direct_declarator
-  (cp_parser *, cp_parser_declarator_kind, int *, bool);
+  (cp_parser *, cp_parser_declarator_kind, int *, bool, bool);
 static enum tree_code cp_parser_ptr_operator
   (cp_parser *, tree *, cp_cv_quals *, tree *);
 static cp_cv_quals cp_parser_cv_qualifier_seq_opt
@@ -10014,7 +10014,8 @@ cp_parser_condition (cp_parser* parser)
       declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
-					 /*member_p=*/false);
+					 /*member_p=*/false,
+					 /*friend_p=*/false);
       /* Parse the attributes.  */
       attributes = cp_parser_attributes_opt (parser);
       /* Parse the asm-specification.  */
@@ -14160,7 +14161,8 @@ cp_parser_explicit_instantiation (cp_parser* parse
 	= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 				/*ctor_dtor_or_conv_p=*/NULL,
 				/*parenthesized_p=*/NULL,
-				/*member_p=*/false);
+				/*member_p=*/false,
+				/*friend_p=*/false);
       if (declares_class_or_enum & 2)
 	cp_parser_check_for_definition_in_return_type (declarator,
 						       decl_specifiers.type,
@@ -16570,7 +16572,7 @@ cp_parser_init_declarator (cp_parser* parser,
     = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 			    &ctor_dtor_or_conv_p,
 			    /*parenthesized_p=*/NULL,
-			    member_p);
+			    member_p, /*friend_p=*/false);
   /* Gather up the deferred checks.  */
   stop_deferring_access_checks ();
 
@@ -16958,14 +16960,17 @@ cp_parser_init_declarator (cp_parser* parser,
    If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff
    the declarator is a direct-declarator of the form "(...)".
 
-   MEMBER_P is true iff this declarator is a member-declarator.  */
+   MEMBER_P is true iff this declarator is a member-declarator.
 
+   If FRIEND_P is true, the declarator is preceded by the `friend'
+   specifier.  */
+
 static cp_declarator *
 cp_parser_declarator (cp_parser* parser,
 		      cp_parser_declarator_kind dcl_kind,
 		      int* ctor_dtor_or_conv_p,
 		      bool* parenthesized_p,
-		      bool member_p)
+		      bool member_p, bool friend_p)
 {
   cp_declarator *declarator;
   enum tree_code code;
@@ -17005,7 +17010,8 @@ cp_parser_declarator (cp_parser* parser,
       declarator = cp_parser_declarator (parser, dcl_kind,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
-					 /*member_p=*/false);
+					 /*member_p=*/false,
+					 friend_p);
 
       /* If we are parsing an abstract-declarator, we must handle the
 	 case where the dependent declarator is absent.  */
@@ -17024,7 +17030,7 @@ cp_parser_declarator (cp_parser* parser,
 						   CPP_OPEN_PAREN);
       declarator = cp_parser_direct_declarator (parser, dcl_kind,
 						ctor_dtor_or_conv_p,
-						member_p);
+						member_p, friend_p);
     }
 
   if (gnu_attributes && declarator && declarator != cp_error_declarator)
@@ -17058,14 +17064,14 @@ cp_parser_declarator (cp_parser* parser,
    we are parsing a direct-declarator.  It is
    CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case
    of ambiguity we prefer an abstract declarator, as per
-   [dcl.ambig.res].  CTOR_DTOR_OR_CONV_P and MEMBER_P are as for
-   cp_parser_declarator.  */
+   [dcl.ambig.res].  CTOR_DTOR_OR_CONV_P, MEMBER_P, and FRIEND_P are
+   as for cp_parser_declarator.  */
 
 static cp_declarator *
 cp_parser_direct_declarator (cp_parser* parser,
 			     cp_parser_declarator_kind dcl_kind,
 			     int* ctor_dtor_or_conv_p,
-			     bool member_p)
+			     bool member_p, bool friend_p)
 {
   cp_token *token;
   cp_declarator *declarator = NULL;
@@ -17246,7 +17252,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 	      declarator
 		= cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
-					member_p);
+					member_p, friend_p);
 	      parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
 	      first = false;
 	      /* Expect a `)'.  */
@@ -17492,6 +17498,7 @@ cp_parser_direct_declarator (cp_parser* parser,
 				for an anonymous type, even if the type
 				got a name for linkage purposes.  */
 			     !TYPE_WAS_ANONYMOUS (class_type)
+			     && !friend_p
 			     && constructor_name_p (unqualified_name,
 						    class_type))
 		      {
@@ -18035,7 +18042,8 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_te
   abstract_declarator
     = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
 			    /*parenthesized_p=*/NULL,
-			    /*member_p=*/false);
+			    /*member_p=*/false,
+			    /*friend_p=*/false);
   /* Check to see if there really was a declarator.  */
   if (!cp_parser_parse_definitely (parser))
     abstract_declarator = NULL;
@@ -18610,7 +18618,8 @@ cp_parser_parameter_declaration (cp_parser *parser
 					 CP_PARSER_DECLARATOR_EITHER,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 parenthesized_p,
-					 /*member_p=*/false);
+					 /*member_p=*/false,
+					 /*friend_p=*/false);
       parser->default_arg_ok_p = saved_default_arg_ok_p;
       /* After the declarator, allow more attributes.  */
       decl_specifiers.attributes
@@ -20446,8 +20455,20 @@ cp_parser_member_declaration (cp_parser* parser)
 		= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					&ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
-					/*member_p=*/true);
+					/*member_p=*/true,
+					friend_p
+					/* With -fpermissive we want to accept:
 
+					   struct S {
+					     struct T{};
+					     friend S::S(T);
+					   };
+
+					   thus also check the return type
+					   to do the right thing later in
+					   cp_parser_direct_declarator.  */
+					&& decl_specifiers.type);
+
 	      /* If something went wrong parsing the declarator, make sure
 		 that we at least consume some tokens.  */
 	      if (declarator == cp_error_declarator)
@@ -21274,7 +21295,8 @@ cp_parser_exception_declaration (cp_parser* parser
     declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
 				       /*ctor_dtor_or_conv_p=*/NULL,
 				       /*parenthesized_p=*/NULL,
-				       /*member_p=*/false);
+				       /*member_p=*/false,
+				       /*friend_p=*/false);
 
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
@@ -24820,7 +24842,8 @@ cp_parser_cache_defarg (cp_parser *parser, bool ns
 		  cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					&ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
-					/*member_p=*/true);
+					/*member_p=*/true,
+					/*friend_p=*/false);
 		}
 	      else
 		{
@@ -26106,7 +26129,8 @@ cp_parser_objc_class_ivars (cp_parser* parser)
 		= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
 					&ctor_dtor_or_conv_p,
 					/*parenthesized_p=*/NULL,
-					/*member_p=*/false);
+					/*member_p=*/false,
+					/*friend_p=*/false);
 	    }
 
 	  /* Look for attributes that apply to the ivar.  */
@@ -26657,7 +26681,7 @@ cp_parser_objc_struct_declaration (cp_parser *pars
 
       /* Parse the declarator.  */
       declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
-					 NULL, NULL, false);
+					 NULL, NULL, false, false);
 
       /* Look for attributes that apply to the ivar.  */
       attributes = cp_parser_attributes_opt (parser);
@@ -29170,7 +29194,8 @@ cp_parser_omp_for_loop_init (cp_parser *parser,
 					 CP_PARSER_DECLARATOR_NAMED,
 					 /*ctor_dtor_or_conv_p=*/NULL,
 					 /*parenthesized_p=*/NULL,
-					 /*member_p=*/false);
+					 /*member_p=*/false,
+					 /*friend_p=*/false);
       attributes = cp_parser_attributes_opt (parser);
       asm_specification = cp_parser_asm_specification_opt (parser);
 


More information about the Gcc-patches mailing list