From patchwork Mon Sep 19 12:25:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1296 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5044:0:0:0:0:0 with SMTP id h4csp936887wrt; Mon, 19 Sep 2022 05:27:18 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7IkHINxh7gPDpSBjz7xQLUTZEWnu9NNVDzZIF2i1zOgKP1FbaTrmigk0ExV7GvMTxUmVOp X-Received: by 2002:a05:6402:348b:b0:450:28be:d6b0 with SMTP id v11-20020a056402348b00b0045028bed6b0mr15736271edc.386.1663590437768; Mon, 19 Sep 2022 05:27:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1663590437; cv=none; d=google.com; s=arc-20160816; b=cz+tjIuCjxatG4kbxiVyP3df1o+8t3NNkaht/YtXRHZdb9bxLMHTWEBEGsV93Bb1tL iEWdXRSSuLAlwKXS5pgrvTJz//xybd4z35onzrJye/RkQjYVEifbkSo3hHkMaijsFNBb Zp3f3Wn3tuXjMWE9k7WTihyLGZ3+T+MFX/SrH1c27xVeQ8byjdNXDvR+iBVC8W30UqD3 GNwi2fYCg3b+pnt7AlOFMMAz8fZWgyX9v03TyOngcNAC0oPDiy+C7ILZYKsB4TXbBW8b cmvMJZ6VCvYycmK23eeb+nhB+4Fvx6oSuCfb3/lJhfyUeBiHzqbKRbgHnxC3dTrn2puJ TgfQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:reply-to:from:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :content-disposition:in-reply-to:mime-version:references:message-id :subject:to:date:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=rUWGQpVdgDdXSqzVqOPV/QXUWoD6AomCIBENe31QBXA=; b=ou4ea7PRTliWdkGaEZrCIZAz/YfNFyk8rp53GbKpcsVuwRgLcHblpXljW00d/ZBSP6 I5c7DMQVTbRP5IDuRKkca5SZpDp/LwiBG9UY11Ru55p21cC75HOyLMa3B1RUjqCCTC0W y8DNkkbmw68vR/gOL4I3hmXkN9ZfjTLhx4DoM0y7DEoK4r6R8ceEgpdTqcpvPLkavCXT xNv8ZqUZJbtatYuvJawImBvliZr0/e64xyZdBRYYWBm1NfyhrLAw8fGalFd9LAaz60gh Ouh60e+YUK6/7PCcfjBH6yDpaXRgN7P6tl0V7pfeJ4U5E8aSfLTDckATaY0sJGMzJRnf RJSA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Xfl+5E+R; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id s17-20020aa7c551000000b00453bc1fda81si5425219edr.556.2022.09.19.05.27.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 19 Sep 2022 05:27:17 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Xfl+5E+R; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 12023385C019 for ; Mon, 19 Sep 2022 12:26:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 12023385C019 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1663590410; bh=rUWGQpVdgDdXSqzVqOPV/QXUWoD6AomCIBENe31QBXA=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Xfl+5E+RCWqnMBC8+isDI7c3DKkxJwJeoN+pamcv86OeL/5Eacqus7mSEFkX9g+JA KzA9sja0SmcLmmj/ZqEFOzO65CIXB/Dm28HT/X7hQRsAkL0gpKyRs8xVc5nwxYhyRm w8oyo76JOY7yHds6QWfJbrTFdq9gqQ+bMIwuQOfc= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id C416038582A7 for ; Mon, 19 Sep 2022 12:25:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C416038582A7 Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-583-76lG_UlvOMWu9aJhdazK1w-1; Mon, 19 Sep 2022 08:25:57 -0400 X-MC-Unique: 76lG_UlvOMWu9aJhdazK1w-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0CDA48001B8 for ; Mon, 19 Sep 2022 12:25:57 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.192.194]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A429949BB60; Mon, 19 Sep 2022 12:25:56 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 28JCPrQJ650684 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 19 Sep 2022 14:25:54 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 28JCPrFe650683; Mon, 19 Sep 2022 14:25:53 +0200 Date: Mon, 19 Sep 2022 14:25:53 +0200 To: Jason Merrill Subject: [PATCH] c++, v2: Implement C++23 P1169R4 - static operator() [PR106651] Message-ID: References: <35c635ad-118f-63bd-eb58-cd949286e28d@redhat.com> <98c787d4-6e2c-411b-0248-fd7a765e0acc@redhat.com> MIME-Version: 1.0 In-Reply-To: <98c787d4-6e2c-411b-0248-fd7a765e0acc@redhat.com> X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-4.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_SHORT, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Jakub Jelinek via Gcc-patches From: Jakub Jelinek Reply-To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1744401006735444993?= X-GMAIL-MSGID: =?utf-8?q?1744401006735444993?= Hi! On Sat, Sep 17, 2022 at 01:30:08PM +0200, Jason Merrill wrote: Below is an updated patch on top of the https://gcc.gnu.org/pipermail/gcc-patches/2022-September/601788.html patch. > Ah, OK. I don't think you need to check for C++23 or CALL_EXPR at all, just > CONVERSION_RANK of the other candidate conversion. You mean that for C++20 and earlier without static operator () being involved it is impossible to see non-standard conversion on the first argument? I've instrumented GCC during the weekend to log an cases where static_1 != static_2 and log also whether the corresponding arg on non-static has standard-conversion or not and the only cases I saw were with the standard conversion when this static operator () patch wasn't in, all similar to: struct S { int foo (long); static int foo (long long); }; void baz () { S s; s.foo (1); } and I can't imagine how there could be something other than standard conversion for the object on which it is called in those cases. > And I notice that you have winner = -1 in both cases; the first should be > winner = 1. Thanks for noticing that, I actually meant to write winner = -1; in the first and winner = 1; for the second, but that was only because of misreading it that -1 is when cand1 is better. > > > You could use FUNCTION_FIRST_USER_PARM to skip 'this' if present. > > > > Ok, will try. Done. > You can use FUNCTION_FIRST_USER_PARMTYPE instead of the ?:. Done too. > The reformatting of the next two statements seems unnecessary. It is unnecessary (and I left it now out), I was just something that catched my eye that it could be formatted more nicely. > How about > > void f() > { > auto l = [] (auto x) static { return x; }; > int (*p)(int) = l; > } > > ? You're right. Except that we ICE on the above for C++14 and 17 in tsubst_copy_and_build's 20343 else if (identifier_p (templ)) 20344 { 20345 /* C++20 P0846: we can encounter an IDENTIFIER_NODE here when 20346 name lookup found nothing when parsing the template name. */ 20347 gcc_assert (cxx_dialect >= cxx20 || seen_error ()); 20348 RETURN (tid); 20349 } and while for C++20 and 23 we don't, we say error: cannot convert ‘f()::’ to ‘int (*)(int)’ in initialization so I think it is just that the assertion does nothing for C++20/23 and we didn't manage to look up templ > Just as a wild guess, I've tried the attached incremental patch on top of the inline patch below and both the ICEs and errors are gone, but whether that is correct or not sadly no idea. 2022-09-19 Jakub Jelinek PR c++/106651 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Predefine __cpp_static_call_operator=202207L for C++23. gcc/cp/ * cp-tree.h (LAMBDA_EXPR_STATIC_P): Implement C++23 P1169R4 - static operator(). Define. * parser.cc (CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Document that it also allows static. (cp_parser_lambda_declarator_opt): Handle static lambda specifier. (cp_parser_decl_specifier_seq): Allow RID_STATIC for CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR. * decl.cc (grok_op_properties): If operator() isn't a method, use a different error wording, if it is static member function, allow it (for C++20 and older with a pedwarn unless it is a lambda function or template instantiation). * call.cc (joust): Don't ICE if one candidate is static member function and the other is an indirect call. If the parameter conversion on the other candidate is user defined conversion, ellipsis or bad conversion, make static member function candidate a winner for that parameter. * lambda.cc (maybe_add_lambda_conv_op): Handle static lambdas. * error.cc (dump_lambda_function): Print static for static lambdas. gcc/testsuite/ * g++.dg/template/error30.C: Adjust expected diagnostics. * g++.dg/cpp1z/constexpr-lambda13.C: Likewise. * g++.dg/cpp23/feat-cxx2b.C: Test __cpp_static_call_operator. * g++.dg/cpp23/static-operator-call1.C: New test. * g++.dg/cpp23/static-operator-call2.C: New test. * g++.old-deja/g++.jason/operator.C: Adjust expected diagnostics. Jakub 2022-09-19 Jakub Jelinek * lambda.cc (maybe_add_lambda_conv_op): If !thisarg, for decltype_call use callop rather than objfn in prepare_op_call. * g++.dg/cpp23/static-operator-call3.C: New test. --- gcc/cp/lambda.cc.jj 2022-09-19 12:34:46.638522537 +0200 +++ gcc/cp/lambda.cc 2022-09-19 14:19:31.200378854 +0200 @@ -1122,6 +1122,8 @@ maybe_add_lambda_conv_op (tree type) --nargs; call = prepare_op_call (objfn, nargs); } + else + objfn = callop; if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); --- gcc/testsuite/g++.dg/cpp23/static-operator-call3.C.jj 2022-09-19 13:30:27.850765150 +0200 +++ gcc/testsuite/g++.dg/cpp23/static-operator-call3.C 2022-09-19 13:33:04.178620907 +0200 @@ -0,0 +1,10 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++14 } } +// { dg-options "" } + +void +foo () +{ + auto a = [] (auto x) static { return x; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + int (*b) (int) = a; +} --- gcc/cp/cp-tree.h.jj 2022-09-13 18:57:29.356969560 +0200 +++ gcc/cp/cp-tree.h 2022-09-19 11:53:19.780594924 +0200 @@ -504,6 +504,7 @@ extern GTY(()) tree cp_global_trees[CPTI OVL_NESTED_P (in OVERLOAD) DECL_MODULE_EXPORT_P (in _DECL) PACK_EXPANSION_FORCE_EXTRA_ARGS_P (in *_PACK_EXPANSION) + LAMBDA_EXPR_STATIC_P (in LAMBDA_EXPR) 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, CALL_EXPR, or FIELD_DECL). @@ -1488,6 +1489,10 @@ enum cp_lambda_default_capture_mode_type #define LAMBDA_EXPR_CAPTURE_OPTIMIZED(NODE) \ TREE_LANG_FLAG_2 (LAMBDA_EXPR_CHECK (NODE)) +/* Predicate tracking whether the lambda was declared 'static'. */ +#define LAMBDA_EXPR_STATIC_P(NODE) \ + TREE_LANG_FLAG_3 (LAMBDA_EXPR_CHECK (NODE)) + /* True if this TREE_LIST in LAMBDA_EXPR_CAPTURE_LIST is for an explicit capture. */ #define LAMBDA_CAPTURE_EXPLICIT_P(NODE) \ --- gcc/cp/parser.cc.jj 2022-09-19 11:52:53.140960839 +0200 +++ gcc/cp/parser.cc 2022-09-19 12:11:15.891823798 +0200 @@ -1994,7 +1994,7 @@ enum constexpr. */ CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8, /* When parsing a decl-specifier-seq, only allow mutable, constexpr or - for C++20 consteval. */ + for C++20 consteval or for C++23 static. */ CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10, /* When parsing a decl-specifier-seq, allow missing typename. */ CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20, @@ -11719,6 +11719,18 @@ cp_parser_lambda_declarator_opt (cp_pars LAMBDA_EXPR_MUTABLE_P (lambda_expr) = 1; quals = TYPE_UNQUALIFIED; } + else if (lambda_specs.storage_class == sc_static) + { + if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) != CPLD_NONE + || LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)) + error_at (lambda_specs.locations[ds_storage_class], + "% lambda specifier with lambda capture"); + else + { + LAMBDA_EXPR_STATIC_P (lambda_expr) = 1; + quals = TYPE_UNQUALIFIED; + } + } tx_qual = cp_parser_tx_qualifier_opt (parser); if (omitted_parms_loc && tx_qual) @@ -11804,6 +11816,12 @@ cp_parser_lambda_declarator_opt (cp_pars if (lambda_specs.locations[ds_consteval]) return_type_specs.locations[ds_consteval] = lambda_specs.locations[ds_consteval]; + if (LAMBDA_EXPR_STATIC_P (lambda_expr)) + { + return_type_specs.storage_class = sc_static; + return_type_specs.locations[ds_storage_class] + = lambda_specs.locations[ds_storage_class]; + } p = obstack_alloc (&declarator_obstack, 0); @@ -11827,8 +11845,9 @@ cp_parser_lambda_declarator_opt (cp_pars { DECL_INITIALIZED_IN_CLASS_P (fco) = 1; DECL_ARTIFICIAL (fco) = 1; - /* Give the object parameter a different name. */ - DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier; + if (!LAMBDA_EXPR_STATIC_P (lambda_expr)) + /* Give the object parameter a different name. */ + DECL_NAME (DECL_ARGUMENTS (fco)) = closure_identifier; DECL_SET_LAMBDA_FUNCTION (fco, true); } if (template_param_list) @@ -16022,8 +16041,15 @@ cp_parser_decl_specifier_seq (cp_parser* && token->keyword != RID_MUTABLE && token->keyword != RID_CONSTEXPR && token->keyword != RID_CONSTEVAL) - error_at (token->location, "%qD invalid in lambda", - ridpointers[token->keyword]); + { + if (token->keyword != RID_STATIC) + error_at (token->location, "%qD invalid in lambda", + ridpointers[token->keyword]); + else if (cxx_dialect < cxx23) + pedwarn (token->location, OPT_Wc__23_extensions, + "%qD only valid in lambda with %<-std=c++23%> or " + "%<-std=gnu++23%>", ridpointers[token->keyword]); + } if (ds != ds_last) set_and_check_decl_spec_loc (decl_specs, ds, token); --- gcc/cp/decl.cc.jj 2022-09-19 11:52:53.169960441 +0200 +++ gcc/cp/decl.cc 2022-09-19 11:53:19.818594402 +0200 @@ -15294,8 +15294,25 @@ grok_op_properties (tree decl, bool comp an enumeration, or a reference to an enumeration. 13.4.0.6 */ if (! methodp || DECL_STATIC_FUNCTION_P (decl)) { + if (operator_code == CALL_EXPR) + { + if (! DECL_STATIC_FUNCTION_P (decl)) + { + error_at (loc, "%qD must be a member function", decl); + return false; + } + if (cxx_dialect < cxx23 + /* For lambdas we diagnose static lambda specifier elsewhere. */ + && ! LAMBDA_FUNCTION_P (decl) + /* For instantiations, we have diagnosed this already. */ + && ! DECL_USE_TEMPLATE (decl)) + pedwarn (loc, OPT_Wc__23_extensions, "%qD may be a static member " + "function only with %<-std=c++23%> or %<-std=gnu++23%>", decl); + /* There are no further restrictions on the arguments to an + overloaded "operator ()". */ + return true; + } if (operator_code == TYPE_EXPR - || operator_code == CALL_EXPR || operator_code == COMPONENT_REF || operator_code == ARRAY_REF || operator_code == NOP_EXPR) --- gcc/cp/call.cc.jj 2022-09-13 18:57:10.199226101 +0200 +++ gcc/cp/call.cc 2022-09-19 13:28:53.511058032 +0200 @@ -12133,10 +12133,14 @@ joust (struct z_candidate *cand1, struct len = cand1->num_convs; if (len != cand2->num_convs) { - int static_1 = DECL_STATIC_FUNCTION_P (cand1->fn); - int static_2 = DECL_STATIC_FUNCTION_P (cand2->fn); + int static_1 = (TREE_CODE (cand1->fn) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (cand1->fn)); + int static_2 = (TREE_CODE (cand2->fn) == FUNCTION_DECL + && DECL_STATIC_FUNCTION_P (cand2->fn)); - if (DECL_CONSTRUCTOR_P (cand1->fn) + if (TREE_CODE (cand1->fn) == FUNCTION_DECL + && TREE_CODE (cand2->fn) == FUNCTION_DECL + && DECL_CONSTRUCTOR_P (cand1->fn) && is_list_ctor (cand1->fn) != is_list_ctor (cand2->fn)) /* We're comparing a near-match list constructor and a near-match non-list constructor. Just treat them as unordered. */ @@ -12145,9 +12149,20 @@ joust (struct z_candidate *cand1, struct gcc_assert (static_1 != static_2); if (static_1) - off2 = 1; + { + /* C++23 [over.best.ics.general] says: + When the parameter is the implicit object parameter of a static + member function, the implicit conversion sequence is a standard + conversion sequence that is neither better nor worse than any + other standard conversion sequence. */ + if (CONVERSION_RANK (cand2->convs[0]) >= cr_user) + winner = 1; + off2 = 1; + } else { + if (CONVERSION_RANK (cand1->convs[0]) >= cr_user) + winner = -1; off1 = 1; --len; } --- gcc/cp/lambda.cc.jj 2022-09-13 18:57:10.267225191 +0200 +++ gcc/cp/lambda.cc 2022-09-19 12:34:46.638522537 +0200 @@ -1099,7 +1099,9 @@ maybe_add_lambda_conv_op (tree type) tree optype = TREE_TYPE (callop); tree fn_result = TREE_TYPE (optype); - tree thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); + tree thisarg = NULL_TREE; + if (TREE_CODE (optype) == METHOD_TYPE) + thisarg = build_int_cst (TREE_TYPE (DECL_ARGUMENTS (callop)), 0); if (generic_lambda_p) { ++processing_template_decl; @@ -1109,18 +1111,22 @@ maybe_add_lambda_conv_op (tree type) return expression for a deduced return call op to allow for simple implementation of the conversion operator. */ - tree instance = cp_build_fold_indirect_ref (thisarg); tree objfn = lookup_template_function (DECL_NAME (callop), DECL_TI_ARGS (callop)); - objfn = build_min (COMPONENT_REF, NULL_TREE, - instance, objfn, NULL_TREE); - int nargs = list_length (DECL_ARGUMENTS (callop)) - 1; + int nargs = list_length (DECL_ARGUMENTS (callop)); + if (thisarg) + { + tree instance = cp_build_fold_indirect_ref (thisarg); + objfn = build_min (COMPONENT_REF, NULL_TREE, + instance, objfn, NULL_TREE); + --nargs; + call = prepare_op_call (objfn, nargs); + } - call = prepare_op_call (objfn, nargs); if (type_uses_auto (fn_result)) decltype_call = prepare_op_call (objfn, nargs); } - else + else if (thisarg) { direct_argvec = make_tree_vector (); direct_argvec->quick_push (thisarg); @@ -1135,9 +1141,11 @@ maybe_add_lambda_conv_op (tree type) tree fn_args = NULL_TREE; { int ix = 0; - tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); + tree src = FUNCTION_FIRST_USER_PARM (callop); tree tgt = NULL; + if (!thisarg && !decltype_call) + src = NULL_TREE; while (src) { tree new_node = copy_node (src); @@ -1160,12 +1168,15 @@ maybe_add_lambda_conv_op (tree type) if (generic_lambda_p) { tree a = tgt; - if (DECL_PACK_P (tgt)) + if (thisarg) { - a = make_pack_expansion (a); - PACK_EXPANSION_LOCAL_P (a) = true; + if (DECL_PACK_P (tgt)) + { + a = make_pack_expansion (a); + PACK_EXPANSION_LOCAL_P (a) = true; + } + CALL_EXPR_ARG (call, ix) = a; } - CALL_EXPR_ARG (call, ix) = a; if (decltype_call) { @@ -1193,7 +1204,7 @@ maybe_add_lambda_conv_op (tree type) tf_warning_or_error); } } - else + else if (thisarg) { /* Don't warn on deprecated or unavailable lambda declarations, unless the lambda is actually called. */ @@ -1203,10 +1214,14 @@ maybe_add_lambda_conv_op (tree type) direct_argvec->address ()); } - CALL_FROM_THUNK_P (call) = 1; - SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + if (thisarg) + { + CALL_FROM_THUNK_P (call) = 1; + SET_EXPR_LOCATION (call, UNKNOWN_LOCATION); + } - tree stattype = build_function_type (fn_result, FUNCTION_ARG_CHAIN (callop)); + tree stattype + = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE (callop)); stattype = (cp_build_type_attribute_variant (stattype, TYPE_ATTRIBUTES (optype))); if (flag_noexcept_type @@ -1249,6 +1264,41 @@ maybe_add_lambda_conv_op (tree type) add_method (type, fn, false); + if (thisarg == NULL_TREE) + { + /* For static lambda, just return operator(). */ + if (nested) + push_function_context (); + else + /* Still increment function_depth so that we don't GC in the + middle of an expression. */ + ++function_depth; + + /* Generate the body of the conversion op. */ + + start_preparsed_function (convfn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + tree body = begin_function_body (); + tree compound_stmt = begin_compound_stmt (0); + + /* decl_needed_p needs to see that it's used. */ + TREE_USED (callop) = 1; + finish_return_stmt (decay_conversion (callop, tf_warning_or_error)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + fn = finish_function (/*inline_p=*/true); + if (!generic_lambda_p) + expand_or_defer_fn (fn); + + if (nested) + pop_function_context (); + else + --function_depth; + return; + } + /* Generic thunk code fails for varargs; we'll complain in mark_used if the conversion op is used. */ if (varargs_function_p (callop)) --- gcc/cp/error.cc.jj 2022-09-13 18:57:10.249225432 +0200 +++ gcc/cp/error.cc 2022-09-19 11:53:19.851593949 +0200 @@ -1692,7 +1692,13 @@ dump_lambda_function (cxx_pretty_printer { /* A lambda's signature is essentially its "type". */ dump_type (pp, DECL_CONTEXT (fn), flags); - if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) & TYPE_QUAL_CONST)) + if (TREE_CODE (TREE_TYPE (fn)) == FUNCTION_TYPE) + { + pp->padding = pp_before; + pp_c_ws_string (pp, "static"); + } + else if (!(TYPE_QUALS (class_of_this_parm (TREE_TYPE (fn))) + & TYPE_QUAL_CONST)) { pp->padding = pp_before; pp_c_ws_string (pp, "mutable"); --- gcc/c-family/c-cppbuiltin.cc.jj 2022-09-13 18:57:10.128227052 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2022-09-19 11:53:19.873593647 +0200 @@ -1081,6 +1081,7 @@ c_cpp_builtins (cpp_reader *pfile) cpp_define (pfile, "__cpp_constexpr=202110L"); cpp_define (pfile, "__cpp_multidimensional_subscript=202110L"); cpp_define (pfile, "__cpp_named_character_escapes=202207L"); + cpp_define (pfile, "__cpp_static_call_operator=202207L"); } if (flag_concepts) { --- gcc/testsuite/g++.dg/template/error30.C.jj 2020-07-28 15:39:10.020756063 +0200 +++ gcc/testsuite/g++.dg/template/error30.C 2022-09-19 11:53:19.880593550 +0200 @@ -2,4 +2,4 @@ template struct A; -template class B> A::x> operator() (); // { dg-error "51:.A::x> operator\\(\\)\\(\\). must be a non-static member function" } +template class B> A::x> operator() (); // { dg-error "51:.A::x> operator\\(\\)\\(\\). must be a member function" } --- gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C.jj 2020-01-12 11:54:37.127402637 +0100 +++ gcc/testsuite/g++.dg/cpp1z/constexpr-lambda13.C 2022-09-19 12:47:20.398209828 +0200 @@ -2,4 +2,4 @@ auto l1 = []() constexpr constexpr { }; // { dg-error "duplicate" } auto l2 = []() mutable mutable { }; // { dg-error "duplicate" } -auto l3 = []() static { }; // { dg-error "static" } +auto l3 = []() static { }; // { dg-error "static' only valid in lambda with" "" { target c++20_down } } --- gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C.jj 2022-09-13 18:57:10.408223302 +0200 +++ gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 2022-09-19 11:53:19.907593180 +0200 @@ -563,3 +563,9 @@ #elif __cpp_named_character_escapes != 202207 # error "__cpp_named_character_escapes != 202207" #endif + +#ifndef __cpp_static_call_operator +# error "__cpp_static_call_operator" +#elif __cpp_static_call_operator != 202207 +# error "__cpp_static_call_operator != 202207" +#endif --- gcc/testsuite/g++.dg/cpp23/static-operator-call1.C.jj 2022-09-19 11:53:19.908593166 +0200 +++ gcc/testsuite/g++.dg/cpp23/static-operator-call1.C 2022-09-19 13:32:10.095362732 +0200 @@ -0,0 +1,41 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++11 } } +// { dg-options "" } + +template +struct S +{ + static constexpr bool operator () (T const &x, T const &y) { return x < y; }; // { dg-warning "may be a static member function only with" "" { target c++20_down } } + using P = bool (*) (T const &, T const &); + operator P () const { return operator (); } +}; + +static_assert (S {} (1, 2), ""); + +template +void +bar (T &x) +{ + x (1, 2); +} + +void +foo () +{ +#if __cpp_constexpr >= 201603L + auto a = [](int x, int y) static constexpr { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target { c++17 && c++20_down } } } + static_assert (a (1, 2) == 3, ""); + bar (*a); +#endif + auto b = []() static { return 1; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + b (); + auto c = [](int x, int y) static { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } } + c (1, 2); + bar (*c); +#if __cpp_generic_lambdas >= 201707L + auto d = [](T x, U y) static { return x + y; }; // { dg-warning "'static' only valid in lambda with" "" { target c++20_only } } + d (1, 2L); +#endif + S s; + s(1L, 2L); +} --- gcc/testsuite/g++.dg/cpp23/static-operator-call2.C.jj 2022-09-19 11:53:19.908593166 +0200 +++ gcc/testsuite/g++.dg/cpp23/static-operator-call2.C 2022-09-19 12:54:54.226996543 +0200 @@ -0,0 +1,22 @@ +// P1169R4 - static operator() +// { dg-do compile { target c++11 } } +// { dg-options "" } + +void +foo () +{ + int u = 0; + auto a = [](int x, int y) mutable mutable { return x + y; }; // { dg-error "duplicate 'mutable' specifier" } + auto b = [](int x, int y) static static { return x + y; }; // { dg-error "duplicate 'static' specifier" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto c = [](int x, int y) static mutable { return x + y; }; // { dg-error "'mutable' specifier conflicts with 'static'" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto d = [](int x, int y) mutable static { return x + y; }; // { dg-error "'static' specifier conflicts with 'mutable'" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto e = [=](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto f = [&](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } + auto g = [u](int x, int y) static { return x + y; }; // { dg-error "lambda specifier with lambda capture" } + // { dg-warning "'static' only valid in lambda with" "" { target c++20_down } .-1 } +} --- gcc/testsuite/g++.old-deja/g++.jason/operator.C.jj 2020-07-28 15:39:10.024756008 +0200 +++ gcc/testsuite/g++.old-deja/g++.jason/operator.C 2022-09-19 11:53:19.918593029 +0200 @@ -6,7 +6,7 @@ typedef __SIZE_TYPE__ size_t; struct A { int operator?:(int a, int b); // { dg-error "prohibits overloading" } - static int operator()(int a); // { dg-error "14:.static int A::operator\\(\\)\\(int\\). must be a non-static member function" } + static int operator()(int a); // { dg-warning "14:.static int A::operator\\(\\)\\(int\\). may be a static member function only with" "" { target c++20_down } } static int operator+(A,A); // { dg-error "14:.static int A::operator\\+\\(A, A\\). must be either a non-static member function or a non-member function" } int operator+(int a, int b = 1); // { dg-error "7:.int A::operator\\+\\(int, int\\). must have either zero or one argument" } int operator++(char); // { dg-error "7:postfix .int A::operator\\+\\+\\(char\\). must have .int. as its argument" }