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.
//////////////////////////
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);
+};
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);