c++: Implement P1102R2 - Down with ()!

The following patch implements P1102R2.
For attributes, we have already attribute parsing before the parameter
declarations and so when that is omitted, if the attributes are first we
already accept it.

2021-02-26  Jakub Jelinek  <jakub@redhat.com>

	* parser.c (cp_parser_lambda_declarator_opt): Implement
	P1102R2 - Down with ()! Make ()s optional before lambda specifiers
	for -std={c,gnu}++2b or with pedwarn in earlier versions.

	* g++.dg/cpp23/lambda-specifiers1.C: New test.
This commit is contained in:
Jakub Jelinek 2021-02-26 10:44:52 +01:00
parent 27f9a87886
commit 0f161cc849
2 changed files with 93 additions and 35 deletions

View File

@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
/* Parse the (optional) middle of a lambda expression.
lambda-declarator:
( parameter-declaration-clause )
decl-specifier-seq [opt]
noexcept-specifier [opt]
attribute-specifier-seq [opt]
trailing-return-type [opt]
requires-clause [opt]
( parameter-declaration-clause ) lambda-specifiers requires-clause [opt]
lambda-specifiers (C++23)
lambda-specifiers:
decl-specifier-seq [opt] noexcept-specifier [opt]
attribute-specifier-seq [opt] trailing-return-type [opt]
LAMBDA_EXPR is the current representation of the lambda expression. */
@ -11248,6 +11248,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
tree tx_qual = NULL_TREE;
tree return_type = NULL_TREE;
tree trailing_requires_clause = NULL_TREE;
bool has_param_list = false;
location_t omitted_parms_loc = UNKNOWN_LOCATION;
cp_decl_specifier_seq lambda_specs;
clear_decl_specs (&lambda_specs);
/* A lambda op() is const unless explicitly 'mutable'. */
@ -11334,42 +11336,80 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
"default argument specified for lambda parameter");
parens.require_close (parser);
has_param_list = true;
}
else if (cxx_dialect < cxx23)
omitted_parms_loc = cp_lexer_peek_token (parser->lexer)->location;
/* In the decl-specifier-seq of the lambda-declarator, each
decl-specifier shall either be mutable or constexpr. */
int declares_class_or_enum;
if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
&& !cp_next_tokens_can_be_gnu_attribute_p (parser))
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
if (lambda_specs.storage_class == sc_mutable)
{
LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
quals = TYPE_UNQUALIFIED;
if (lambda_specs.conflicting_specifiers_p)
error_at (lambda_specs.locations[ds_storage_class],
"duplicate %<mutable%>");
}
/* In the decl-specifier-seq of the lambda-declarator, each
decl-specifier shall either be mutable or constexpr. */
int declares_class_or_enum;
if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
&& !cp_next_tokens_can_be_gnu_attribute_p (parser))
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
&lambda_specs, &declares_class_or_enum);
tx_qual = cp_parser_tx_qualifier_opt (parser);
if (omitted_parms_loc && lambda_specs.any_specifiers_p)
{
pedwarn (omitted_parms_loc, 0,
"parameter declaration before lambda declaration "
"specifiers only optional with %<-std=c++2b%> or "
"%<-std=gnu++2b%>");
omitted_parms_loc = UNKNOWN_LOCATION;
}
/* Parse optional exception specification. */
exception_spec
= cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
if (lambda_specs.storage_class == sc_mutable)
{
LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1;
quals = TYPE_UNQUALIFIED;
if (lambda_specs.conflicting_specifiers_p)
error_at (lambda_specs.locations[ds_storage_class],
"duplicate %<mutable%>");
}
std_attrs = cp_parser_std_attribute_spec_seq (parser);
tx_qual = cp_parser_tx_qualifier_opt (parser);
if (omitted_parms_loc && tx_qual)
{
pedwarn (omitted_parms_loc, 0,
"parameter declaration before lambda transaction "
"qualifier only optional with %<-std=c++2b%> or "
"%<-std=gnu++2b%>");
omitted_parms_loc = UNKNOWN_LOCATION;
}
/* Parse optional trailing return type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
cp_lexer_consume_token (parser->lexer);
return_type = cp_parser_trailing_type_id (parser);
}
/* Parse optional exception specification. */
exception_spec
= cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE);
if (cp_next_tokens_can_be_gnu_attribute_p (parser))
gnu_attrs = cp_parser_gnu_attributes_opt (parser);
if (omitted_parms_loc && exception_spec)
{
pedwarn (omitted_parms_loc, 0,
"parameter declaration before lambda exception "
"specification only optional with %<-std=c++2b%> or "
"%<-std=gnu++2b%>");
omitted_parms_loc = UNKNOWN_LOCATION;
}
std_attrs = cp_parser_std_attribute_spec_seq (parser);
/* Parse optional trailing return type. */
if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
if (omitted_parms_loc)
pedwarn (omitted_parms_loc, 0,
"parameter declaration before lambda trailing "
"return type only optional with %<-std=c++2b%> or "
"%<-std=gnu++2b%>");
cp_lexer_consume_token (parser->lexer);
return_type = cp_parser_trailing_type_id (parser);
}
if (cp_next_tokens_can_be_gnu_attribute_p (parser))
gnu_attrs = cp_parser_gnu_attributes_opt (parser);
if (has_param_list)
{
/* Parse optional trailing requires clause. */
trailing_requires_clause = cp_parser_requires_clause_opt (parser, false);

View File

@ -0,0 +1,18 @@
// P1102R2 - Down with ()!
// { dg-do compile { target c++11 } }
// { dg-options "" }
void
foo ()
{
auto a = [] mutable {}; // { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_down } }
#if __cpp_constexpr >= 201603L
auto b = [] constexpr {}; // { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target { c++17 && c++20_down } } }
#endif
#if __cpp_consteval >= 201811L
auto c = [] consteval {}; // { dg-warning "parameter declaration before lambda declaration specifiers only optional with" "" { target c++20_only } }
#endif
auto d = [] throw() {}; // { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
auto e = [] noexcept {}; // { dg-warning "parameter declaration before lambda exception specification only optional with" "" { target c++20_down } }
auto f = [] -> int { return 0; }; // { dg-warning "parameter declaration before lambda trailing return type only optional with" "" { target c++20_down } }
}