Message ID | 20210225184421.GL4020736@tucnak |
---|---|
State | New |
Headers | show |
Series | c++: Implement P1102R2 - Down with ()! | expand |
On 2/25/21 1:44 PM, Jakub Jelinek wrote: > Hi! > > 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. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > Or defer for GCC 12? > > 2021-02-25 Jakub Jelinek <jakub@redhat.com> > > P1102R2 - Down with ()! > * parser.c (cp_parser_lambda_declarator_opt): 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. > > --- gcc/cp/parser.c.jj 2021-02-12 09:58:25.341506456 +0100 > +++ gcc/cp/parser.c 2021-02-25 14:28:37.525431561 +0100 > @@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser* > /* 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_pars > tree tx_qual = NULL_TREE; > tree return_type = NULL_TREE; > tree trailing_requires_clause = NULL_TREE; > + bool has_param_list = false; > + location_t lambda_specifiers_loc = UNKNOWN_LOCATION; Let's call this omitted_parms_loc, since that's what it's used for. > cp_decl_specifier_seq lambda_specs; > clear_decl_specs (&lambda_specs); > /* A lambda op() is const unless explicitly 'mutable'. */ > @@ -11334,47 +11336,88 @@ cp_parser_lambda_declarator_opt (cp_pars > "default argument specified for lambda parameter"); > > parens.require_close (parser); > + has_param_list = true; > + } > + else if (cxx_dialect < cxx23) > + lambda_specifiers_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); > + > + if (lambda_specifiers_loc > + && (lambda_specs.storage_class == sc_mutable > + || lambda_specs.locations[ds_constexpr] > + || lambda_specs.locations[ds_consteval])) Maybe lambda_specs.any_specifiers_p instead of checking them individually? > + { > + pedwarn (lambda_specifiers_loc, 0, > + "parameter declaration before lambda declaration " > + "specifiers only optional with %<-std=c++2b%> or " > + "%<-std=gnu++2b%>"); > + lambda_specifiers_loc = UNKNOWN_LOCATION; > + } > + > + 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%>"); > + } > + > + tx_qual = cp_parser_tx_qualifier_opt (parser); > + if (lambda_specifiers_loc && tx_qual) > + { > + pedwarn (lambda_specifiers_loc, 0, > + "parameter declaration before lambda transaction " > + "qualifier only optional with %<-std=c++2b%> or " > + "%<-std=gnu++2b%>"); > + lambda_specifiers_loc = UNKNOWN_LOCATION; > + } > + > + /* Parse optional exception specification. */ > + exception_spec > + = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); > + > + if (lambda_specifiers_loc && exception_spec) > + { > + pedwarn (lambda_specifiers_loc, 0, > + "parameter declaration before lambda exception " > + "specification only optional with %<-std=c++2b%> or " > + "%<-std=gnu++2b%>"); > + lambda_specifiers_loc = UNKNOWN_LOCATION; > + } > > - tx_qual = cp_parser_tx_qualifier_opt (parser); > + std_attrs = cp_parser_std_attribute_spec_seq (parser); > > - /* Parse optional exception specification. */ > - exception_spec > - = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); > - > - std_attrs = cp_parser_std_attribute_spec_seq (parser); > - > - /* 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 trailing return type. */ > + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) > + { > + if (lambda_specifiers_loc) > + pedwarn (lambda_specifiers_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 (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); > > - /* The function parameters must be in scope all the way until after the > - trailing-return-type in case of decltype. */ > + /* The function parameters must be in scope all the way until after > + the trailing-return-type in case of decltype. */ This rewrapping seems unnecessary. OK for trunk with those changes, this seems safe enough. > pop_bindings_and_leave_scope (); > } > > --- gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C.jj 2021-02-25 14:55:14.719567663 +0100 > +++ gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C 2021-02-25 15:00:36.608082855 +0100 > @@ -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 } } > +} > > Jakub >
--- gcc/cp/parser.c.jj 2021-02-12 09:58:25.341506456 +0100 +++ gcc/cp/parser.c 2021-02-25 14:28:37.525431561 +0100 @@ -11223,12 +11223,12 @@ cp_parser_lambda_introducer (cp_parser* /* 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_pars tree tx_qual = NULL_TREE; tree return_type = NULL_TREE; tree trailing_requires_clause = NULL_TREE; + bool has_param_list = false; + location_t lambda_specifiers_loc = UNKNOWN_LOCATION; cp_decl_specifier_seq lambda_specs; clear_decl_specs (&lambda_specs); /* A lambda op() is const unless explicitly 'mutable'. */ @@ -11334,47 +11336,88 @@ cp_parser_lambda_declarator_opt (cp_pars "default argument specified for lambda parameter"); parens.require_close (parser); + has_param_list = true; + } + else if (cxx_dialect < cxx23) + lambda_specifiers_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); + + if (lambda_specifiers_loc + && (lambda_specs.storage_class == sc_mutable + || lambda_specs.locations[ds_constexpr] + || lambda_specs.locations[ds_consteval])) + { + pedwarn (lambda_specifiers_loc, 0, + "parameter declaration before lambda declaration " + "specifiers only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + lambda_specifiers_loc = UNKNOWN_LOCATION; + } + + 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%>"); + } + + tx_qual = cp_parser_tx_qualifier_opt (parser); + if (lambda_specifiers_loc && tx_qual) + { + pedwarn (lambda_specifiers_loc, 0, + "parameter declaration before lambda transaction " + "qualifier only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + lambda_specifiers_loc = UNKNOWN_LOCATION; + } + + /* Parse optional exception specification. */ + exception_spec + = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); + + if (lambda_specifiers_loc && exception_spec) + { + pedwarn (lambda_specifiers_loc, 0, + "parameter declaration before lambda exception " + "specification only optional with %<-std=c++2b%> or " + "%<-std=gnu++2b%>"); + lambda_specifiers_loc = UNKNOWN_LOCATION; + } - tx_qual = cp_parser_tx_qualifier_opt (parser); + std_attrs = cp_parser_std_attribute_spec_seq (parser); - /* Parse optional exception specification. */ - exception_spec - = cp_parser_exception_specification_opt (parser, CP_PARSER_FLAGS_NONE); - - std_attrs = cp_parser_std_attribute_spec_seq (parser); - - /* 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 trailing return type. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) + { + if (lambda_specifiers_loc) + pedwarn (lambda_specifiers_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 (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); - /* The function parameters must be in scope all the way until after the - trailing-return-type in case of decltype. */ + /* The function parameters must be in scope all the way until after + the trailing-return-type in case of decltype. */ pop_bindings_and_leave_scope (); } --- gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C.jj 2021-02-25 14:55:14.719567663 +0100 +++ gcc/testsuite/g++.dg/cpp23/lambda-specifiers1.C 2021-02-25 15:00:36.608082855 +0100 @@ -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 } } +}