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 [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id EA2863858D37 for ; Tue, 27 Sep 2022 02:27:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EA2863858D37 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1664245658; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vRnmm8PXYf9MxDNjjh76I9zFx5pwrVaUEot49nxcln8=; b=KlYtvlCEnevQ+8/yYJZrH7GZErDmQfeoiOm7pXTahkSk2HOWN5VhrLCjPR5DVtFwO6+75m Zn2Sc7mdy6/fZxlaTUTAy840dwSZQtmvYmqUoTrABEOC2mCmFNiDltlfdUAmSqVJFlPFg/ 6YhylpauMapDg3peBZ0hhnQPALe5kjs= Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-279-62uGVqURMEyzyD5v0QiIGA-1; Mon, 26 Sep 2022 22:27:37 -0400 X-MC-Unique: 62uGVqURMEyzyD5v0QiIGA-1 Received: by mail-qt1-f197.google.com with SMTP id w4-20020a05622a134400b0035cbc5ec9a2so5963333qtk.14 for ; Mon, 26 Sep 2022 19:27:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date; bh=vRnmm8PXYf9MxDNjjh76I9zFx5pwrVaUEot49nxcln8=; b=R2boT36pj3L1Scov3YLhUSpD8+JwanYxCyhCic3RTAPM2s1qD34JGESSsWGGKaU8rI aUExlPocem3pr4nlydpZyS8JNDfrJWl4XMlqhi2QYlsUDF80thDiMQ5QCZy8rEDxpJjG fMI6wAL/U69dRY0QIbtToq2SL1ZL5MsiUw0c53gPaOWXaXKRUjgK8Az3iukB0q8wa+Hr Pfb9Akn9NAkbz4X31TsUIZVfk5tzAgMT4RVZNms2Uos5iyUOn9FcZgi1x3fcZQcNRS6+ f5JyXdVVQMM1tVSyquwu/x4UFmvZJvV/NuydAsNUkDIXh9gQPrrahHgUAXs2xxaHtFaM I02A== X-Gm-Message-State: ACrzQf34845QjOnzaHxNyOFUlAu5HStB1mKOMG2P9FSzEPywFbo0OP9B BeIza4Ri/unwlC1CA6DaPio6QI8Cd8eOQuyUQ9ynhXWo99JOOJM3fXOudnagWRJaHhPXw6df9Fz H9+TSBdOchz+XFrktCA== X-Received: by 2002:a05:6214:21ee:b0:4aa:b123:816b with SMTP id p14-20020a05621421ee00b004aab123816bmr19869628qvj.83.1664245655993; Mon, 26 Sep 2022 19:27:35 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6J7W/BmUIIMst11E9bB+HBXeZnj6t5RY/0qcmSHb9ubIu9gonOomso55g+J3D+5eA7w7AxWQ== X-Received: by 2002:a05:6214:21ee:b0:4aa:b123:816b with SMTP id p14-20020a05621421ee00b004aab123816bmr19869614qvj.83.1664245655542; Mon, 26 Sep 2022 19:27:35 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id q14-20020a37f70e000000b006bba46e5eeasm182809qkj.37.2022.09.26.19.27.34 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 26 Sep 2022 19:27:34 -0700 (PDT) Message-ID: <4f3f00fb-e4ec-5d7f-ff8f-2445abd314cd@redhat.com> Date: Mon, 26 Sep 2022 22:27:34 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.1 Subject: Re: [PATCH] c++, v2: Implement C++23 P1169R4 - static operator() [PR106651] To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org References: <35c635ad-118f-63bd-eb58-cd949286e28d@redhat.com> <98c787d4-6e2c-411b-0248-fd7a765e0acc@redhat.com> From: Jason Merrill In-Reply-To: X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,KAM_SHORT,NICE_REPLY_A,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 List-Id: On 9/19/22 08:25, Jakub Jelinek wrote: > 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 believe so, and even if it were possible the change is correct for earlier standards. > 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. That makes sense. The patch with followup is OK. > 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. > > --- 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" } > > > Jakub