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.133.124]) by sourceware.org (Postfix) with ESMTPS id DEC23382FC5D for ; Sat, 17 Sep 2022 11:30:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DEC23382FC5D 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=1663414213; 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=MNeR/X/DaGfEirEmfNkDZKFdb/EOLwV+5JKKqG+/A70=; b=EMrOElvE8JJtVTXbgiXyjSYKWcK9DxGlZjafUM7pylZrP+6wzkO14kC1G5tpFW2curREJT 2O5Nm1EODl+Vf+TrRWeopo5TdZ5c8QVRDBTt9rNuZHXaVuo8UC+sEupRj18sBZ9/STCsTw DE+2WHaliP0sxbKqSgkK0EONyPgb1fY= Received: from mail-ed1-f69.google.com (mail-ed1-f69.google.com [209.85.208.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-594-W2xBo1XmOzeSLI-LVNz0NA-1; Sat, 17 Sep 2022 07:30:11 -0400 X-MC-Unique: W2xBo1XmOzeSLI-LVNz0NA-1 Received: by mail-ed1-f69.google.com with SMTP id y14-20020a056402440e00b0044301c7ccd9so16760644eda.19 for ; Sat, 17 Sep 2022 04:30:11 -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=MNeR/X/DaGfEirEmfNkDZKFdb/EOLwV+5JKKqG+/A70=; b=y1SGzM0+A92te2WtqajmkiRsMBiOcKg/jGR1AOLJpriqkPBAfpJAnmeZIHupmXO6A4 okmq7umBnDCFZZU704C8TVndvsdeZnKC75s/DyA5XXg3HUCHpXwwXUB1SiPXZII3SPx4 kliayKFq7311k2Io9Ghs4h9ibTIij0PR6pwD2+Gb+mAghcEcPhD6Z7jyuHZmVEXRMJ+g dK/QmdOEm2czvIOA1U0VNwWZ3KwHmjyYTYO7YV9jRaYqgllk762HFmRWgEwSBfwUcviC OskXwnmHkN3fVcYZW+VMYj/BfDrtYiaILRT9L6Kydrz4WSeutcyABShACNetw1dZfOXf n6Eg== X-Gm-Message-State: ACrzQf27Bcuy/QUA2flo1kXC/3xsg3lhsNQNLv77vfZVkojkcuGdgFeH j9PnW0XNax2AotWwo2b2JNTl2NZbwo0iOPrEvBSUdXshMunhbHiBXJeNxqkLHFs9MirEPwcTN8D j8erWAzA6vnaWVLyYrQ== X-Received: by 2002:a05:6402:b6c:b0:44e:2faf:1ba4 with SMTP id cb12-20020a0564020b6c00b0044e2faf1ba4mr7529771edb.191.1663414210339; Sat, 17 Sep 2022 04:30:10 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6Pf9zNuexfLBNoVUc5yjy7mNy7LJPMotVfHje5HXTAtGLY2E8Ptrh+hhag6f+Xi/BNWxPHzQ== X-Received: by 2002:a05:6402:b6c:b0:44e:2faf:1ba4 with SMTP id cb12-20020a0564020b6c00b0044e2faf1ba4mr7529754edb.191.1663414210007; Sat, 17 Sep 2022 04:30:10 -0700 (PDT) Received: from [10.9.7.96] (vpn-konference.ms.mff.cuni.cz. [195.113.20.101]) by smtp.gmail.com with ESMTPSA id x24-20020a50d618000000b0044e01e2533asm15927417edi.43.2022.09.17.04.30.08 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 17 Sep 2022 04:30:09 -0700 (PDT) Message-ID: <98c787d4-6e2c-411b-0248-fd7a765e0acc@redhat.com> Date: Sat, 17 Sep 2022 13:30:08 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.0 Subject: Re: [PATCH] c++: Implement C++23 P1169R4 - static operator() [PR106651] To: Jakub Jelinek Cc: gcc-patches@gcc.gnu.org References: <35c635ad-118f-63bd-eb58-cd949286e28d@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: 7bit X-Spam-Status: No, score=-8.5 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,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/17/22 02:42, Jakub Jelinek wrote: > On Sat, Sep 17, 2022 at 01:23:59AM +0200, Jason Merrill wrote: >> On 9/13/22 12:42, Jakub Jelinek wrote: >>> The following patch attempts to implement C++23 P1169R4 - static operator() >>> paper's compiler side (there is some small library side too not implemented >>> yet). This allows static members as user operator() declarations and >>> static specifier on lambdas without lambda capture. As decl specifier >>> parsing doesn't track about the presence and locations of all specifiers, >>> the patch unfortunately replaces the diagnostics about duplicate mutable >>> with diagnostics about conflicting specifiers because the information >>> whether it was mutable mutable, mutable static, static mutable or static >>> static is lost. >> >> I wonder why we don't give an error when setting the >> conflicting_specifiers_p flag in cp_parser_set_storage_class? We should be >> able to give a better diagnostic at that point. > > I will try that. > >>> Beyond this, the synthetized conversion operator changes >>> for static lambdas as it can just return the operator() static method >>> address, doesn't need to create a thunk for it. >>> The change I'm least sure about is the call.cc (joust) change, one thing >>> is that we ICEd because we assumed that len could be different only if >>> both candidates are direct calls but it can be one direct and one indirect >>> call, >> >> How do you mean? > > That is either on the > struct less { > static constexpr auto operator()(int i, int j) -> bool { > return i < j; > } > > using P = bool(*)(int, int); > operator P() const { return operator(); } > }; > > static_assert(less{}(1, 2)); > testcase from the paper (S in static-operator-call1.C) or any static lambda > which also has static operator() and cast operator. > The paper then talks about > operator()(contrived-parameter, int, int); > call-function(bool(*)(int, int), int, int); > which is exactly what caused the ICE, one of the cand?->fn was the static > operator(), the other cand?->fn isn't a FUNCTION_DECL, but a function > pointer (what the cast operator returns). Ah, makes sense. >>> + { >>> + /* 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. >>> + Apply this for C++23 or when the static member function is >>> + overloaded call operator (C++23 feature we accept as an >>> + extension). */ >>> + if ((cxx_dialect >= cxx23 >>> + || (DECL_OVERLOADED_OPERATOR_P (cand1->fn) >>> + && DECL_OVERLOADED_OPERATOR_IS (cand1->fn, CALL_EXPR))) >>> + && CONVERSION_RANK (cand2->convs[0]) >= cr_user) >>> + winner = -1; >> >> I don't know what you're trying to do here. The above passage describes how >> we've always compared static to non-static, which should work the same way >> for operator(). > > It doesn't work for the static operator() case vs. pointer returned by > cast operator, with just the > - 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) > changes in joust so that it doesn't ICE, the call is ambiguous. > Previously the standard had: > "If F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better > nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better > nor worse than ICS1(F); otherwise," > but that was removed and instead: > "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." > was added elsewhere. The code implements the former. We don't have any > conversion for the non-existing object parameter to static, so what I want > to do is keep doing what we were before if the other candidate's conversion > on the first parameter is standard (CONVERSION_RANK (cand2->convs[0]) < cr_user) > and otherwise indicate that the static operator() has there a standard > conversion and so it should be better than any user/ellipsis/bad conversion. > Now, it could be done just for cxx_dialect >= cxx23 as that is pedantically > what the standard says, but if we allow with a pedwarn static operator() > in earlier standards, I think we better treat it there the same, because > otherwise one can't call any static lambdas (all those calls would be > ambiguous). 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. And I notice that you have winner = -1 in both cases; the first should be winner = 1. >>> @@ -1135,9 +1141,13 @@ maybe_add_lambda_conv_op (tree type) >>> tree fn_args = NULL_TREE; >>> { >>> int ix = 0; >>> - tree src = DECL_CHAIN (DECL_ARGUMENTS (callop)); >>> + tree src = DECL_ARGUMENTS (callop); >>> tree tgt = NULL; >>> + if (thisarg) >>> + src = DECL_CHAIN (src); >> >> You could use FUNCTION_FIRST_USER_PARM to skip 'this' if present. > > Ok, will try. > >>> + else if (!decltype_call) >>> + src = NULL_TREE; >>> while (src) >>> { >>> tree new_node = copy_node (src); >>> @@ -1160,12 +1170,15 @@ maybe_add_lambda_conv_op (tree type) >>> if (generic_lambda_p) >>> { >>> tree a = tgt; >>> - if (DECL_PACK_P (tgt)) >>> + if (thisarg) >> >> This is wrong, pack expansion handling has nothing to do with 'this'. Only >> the assignment to CALL_EXPR_ARG should depend on thisarg. > > The point was that make_pack_expansion etc. is only used for what > is later then stored to CALL_EXPR_ARG. As we don't need to construct > call at all for the static lambda case, that looked like wasted effort. Ah, you're right, I thought it was also used for decltype_call. >>> @@ -1203,14 +1216,18 @@ 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)); >>> - stattype = (cp_build_type_attribute_variant >>> - (stattype, TYPE_ATTRIBUTES (optype))); >>> - if (flag_noexcept_type >>> - && TYPE_NOTHROW_P (TREE_TYPE (callop))) >>> + tree stattype >>> + = build_function_type (fn_result, thisarg ? FUNCTION_ARG_CHAIN (callop) >>> + : TYPE_ARG_TYPES (optype)); >>> + stattype = cp_build_type_attribute_variant (stattype, >>> + TYPE_ATTRIBUTES (optype)); >>> + if (flag_noexcept_type && TYPE_NOTHROW_P (TREE_TYPE (callop))) >>> stattype = build_exception_variant (stattype, noexcept_true_spec); >> >> If !thisarg, shouldn't stattype just be optype? No need to rebuild it in >> that case. > > I thought it should be auto-deduced if it isn't yet. Ah, yes, of course. You can use FUNCTION_FIRST_USER_PARMTYPE instead of the ?:. The reformatting of the next two statements seems unnecessary. > If it doesn't need to > be, sure, we wouldn't need to bother with decltype_call for !thisarg > either and just not do the loop on arguments etc. > I've tried to create a testcase where I could see the generic static lambda > but I failed to construct one, even with the template <...> lambda syntax > I can't use a template id of the lambda to instantiate some particular case > and then use *. Would passing a generic lambda to a function with > some function pointer argument trigger it? How about void f() { auto l = [] (auto x) static { return x; }; int (*p)(int) = l; } ? Jason