c++: Fix attributes with lambda and trailing return type.

My fix for 60503 fixed handling of C++11 attributes following the
lambda-declarator.  My patch for 89640 re-added support for GNU attributes,
but attributes after the trailing return type were parsed as applying to the
return type rather than to the function.  This patch adjusts parsing of a
trailing-return-type to ignore GNU attributes at the end of the declaration
so that they will be applied to the declaration as a whole.

I also considered parsing the attributes between the closing paren and the
trailing-return-type, and tried a variety of approaches to implementing
that, but I think it's better to stick with the documented rule that "An
attribute specifier list may appear immediately before the comma, '=' or
semicolon terminating the declaration of an identifier...."  Anyone
disagree?

Meanwhile, C++ committee discussion about the lack of any way to apply
attributes to a lambda op() seems to have concluded that they should go
between the introducer and declarator, so I've implemented that as well.

	PR c++/90333
	PR c++/89640
	PR c++/60503
	* parser.c (cp_parser_type_specifier_seq): Don't parse attributes in
	a trailing return type.
	(cp_parser_lambda_declarator_opt): Parse C++11 attributes before
	parens.
This commit is contained in:
Jason Merrill 2020-01-28 17:41:05 -05:00
parent 165255c7a5
commit 245e40af4f
3 changed files with 40 additions and 1 deletions

View file

@ -1,3 +1,13 @@
2020-01-29 Jason Merrill <jason@redhat.com>
PR c++/90333
PR c++/89640
PR c++/60503
* parser.c (cp_parser_type_specifier_seq): Don't parse attributes in
a trailing return type.
(cp_parser_lambda_declarator_opt): Parse C++11 attributes before
parens.
2020-01-29 Marek Polacek <polacek@redhat.com>
PR c++/91754 - Fix template arguments comparison with class NTTP.

View file

@ -10962,6 +10962,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
++parser->num_template_parameter_lists;
}
/* Committee discussion supports allowing attributes here. */
lambda_specs.attributes = cp_parser_attributes_opt (parser);
/* The parameter-declaration-clause is optional (unless
template-parameter-list was given), but must begin with an
opening parenthesis if present. */
@ -11097,7 +11100,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
fco = grokmethod (&return_type_specs,
declarator,
gnu_attrs);
chainon (gnu_attrs, lambda_specs.attributes));
if (fco != error_mark_node)
{
DECL_INITIALIZED_IN_CLASS_P (fco) = 1;
@ -22277,6 +22280,18 @@ cp_parser_type_specifier_seq (cp_parser* parser,
/* Check for attributes first. */
if (cp_next_tokens_can_be_attribute_p (parser))
{
/* GNU attributes at the end of a declaration apply to the
declaration as a whole, not to the trailing return type. So look
ahead to see if these attributes are at the end. */
if (seen_type_specifier && is_trailing_return
&& cp_next_tokens_can_be_gnu_attribute_p (parser))
{
size_t n = cp_parser_skip_attributes_opt (parser, 1);
cp_token *tok = cp_lexer_peek_nth_token (parser->lexer, n);
if (tok->type == CPP_SEMICOLON || tok->type == CPP_COMMA
|| tok->type == CPP_EQ || tok->type == CPP_OPEN_BRACE)
break;
}
type_specifier_seq->attributes
= attr_chainon (type_specifier_seq->attributes,
cp_parser_attributes_opt (parser));

View file

@ -0,0 +1,14 @@
// PR c++/90333
// { dg-do compile { target c++11 } }
auto l = [] [[nodiscard]] () -> int { return 0; };
auto l2 = []() -> int __attribute ((warn_unused_result)) { return 0; };
auto f() -> int __attribute ((warn_unused_result));
auto f() -> int { return 0; }
int main()
{
l(); // { dg-warning "nodiscard" }
l2(); // { dg-warning "unused_result" }
f(); // { dg-warning "unused_result" }
}