From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 767AB3896838 for ; Thu, 25 Feb 2021 18:44:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 767AB3896838 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-487-kErxJGvQNrCKi5WExOYJjg-1; Thu, 25 Feb 2021 13:44:26 -0500 X-MC-Unique: kErxJGvQNrCKi5WExOYJjg-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 56779107ACE8 for ; Thu, 25 Feb 2021 18:44:25 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-112-197.ams2.redhat.com [10.36.112.197]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E2CCA5D767; Thu, 25 Feb 2021 18:44:24 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 11PIiMU52611095 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 25 Feb 2021 19:44:22 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 11PIiMKZ2611094; Thu, 25 Feb 2021 19:44:22 +0100 Date: Thu, 25 Feb 2021 19:44:21 +0100 From: Jakub Jelinek To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: Implement P1102R2 - Down with ()! Message-ID: <20210225184421.GL4020736@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-6.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Feb 2021 18:44:30 -0000 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 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; 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 %"); - } + /* 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 %"); + } + + 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 } } +} Jakub