Message ID | 20210920164608.2740792-1-ppalka@redhat.com |
---|---|
State | Changes Requested |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 051F8385842B for <patchwork@sourceware.org>; Mon, 20 Sep 2021 16:46:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 051F8385842B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1632156405; bh=spSPVVuX4+gol3O2EV/VZ7Oqz4qqDTgEN5dCqigti84=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=TBdS6eK7TYkGMSmug7McPsHH+9KPFGBmSwkAeUoZz3UH5C4EVnxGAVdQmMfPEguSg OBzDuTP0l8dET3sHjqOJM3bYNbrmdfoy7nC8+MEnmdsWyNGLbRTqrAyK+NvHqHqlFe J1xGp61xQTQwX1gS7+4hj+u5RXXUy8I3GImp6wd4= 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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 0A769385841A for <gcc-patches@gcc.gnu.org>; Mon, 20 Sep 2021 16:46:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0A769385841A Received: from mail-qv1-f69.google.com (mail-qv1-f69.google.com [209.85.219.69]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-507-k_1ryfqlN8abpVO3tli4JA-1; Mon, 20 Sep 2021 12:46:11 -0400 X-MC-Unique: k_1ryfqlN8abpVO3tli4JA-1 Received: by mail-qv1-f69.google.com with SMTP id e6-20020a0cb446000000b0037eeb9851dfso52425835qvf.17 for <gcc-patches@gcc.gnu.org>; Mon, 20 Sep 2021 09:46:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=spSPVVuX4+gol3O2EV/VZ7Oqz4qqDTgEN5dCqigti84=; b=0oI3od1KlrNg8/3ruoAQygymnC0PYFH61eiZut09kJjvt9zBr5lRYN/JjTAHoTtTRW wIoFiWjk8AzH5L5FYwuvZVKRW+Pju658vt0WjPhi4E8o1bZ0FshXmpMKp3QM3cmOSs+Y T2RPdvfuOlQhW5HTqIqNR7/mlz4v/IDa9lOePBJrw2McRMSivifS1h+6sPNq3pISbna3 rMHRQQ6jEiHrG96qobRgNVCe9LRcBVTIaps/L5VJM/nAHVUyij/mCy3viOVRfR8TnAbT R49Ly4qLGCzxteqgqzyEyJkGFIGj3AP1IAtCcfipRoaV13/Gyn6MHZd9PdBddzclT9Wn iyTw== X-Gm-Message-State: AOAM532128UBQctCuLvD9RYgImcXu1dvyq03/9UniiFM0CkFsJHGtLmg VaeT5hQr2fL8A52m49BtHAx7frBSPTB09CJBdvMImboBz1f2uhMCW7iezJYn4KSKgRCWIpzRcdr +nwswddmvh5URw6SFv88H/fOcFT4egtZL79g2wUmvkce/it8HP6OpZO95EX9Nn81Ffzc= X-Received: by 2002:ae9:efc9:: with SMTP id d192mr9060811qkg.366.1632156370921; Mon, 20 Sep 2021 09:46:10 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy4verbEJ5EMSvKsv4meR3Pk+H6s05+GFlP/1BjaIkxS3yL2+cIWwGJJG5L6/irdgvr+n7bdA== X-Received: by 2002:ae9:efc9:: with SMTP id d192mr9060770qkg.366.1632156370553; Mon, 20 Sep 2021 09:46:10 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id e1sm857547qty.79.2021.09.20.09.46.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 20 Sep 2021 09:46:09 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] c++: consider built-in operator candidates first Date: Mon, 20 Sep 2021 12:46:08 -0400 Message-Id: <20210920164608.2740792-1-ppalka@redhat.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-16.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> From: Patrick Palka via Gcc-patches <gcc-patches@gcc.gnu.org> Reply-To: Patrick Palka <ppalka@redhat.com> Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
c++: consider built-in operator candidates first
|
|
Commit Message
Patrick Palka
Sept. 20, 2021, 4:46 p.m. UTC
During operator overload resolution, we currently consider non-member candidates before built-in candidates. This didn't make a difference before r12-3346, but after this change add_candidates will avoid computing excess argument conversions if we've already seen a strictly viable candidate, so it's better to consider built-in candidates first. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? gcc/cp/ChangeLog: * call.c (add_operator_candidates): Consider built-in operator candidates before considering non-member candidates. gcc/testsuite/ChangeLog: * g++.dg/template/conv17.C: Extend test. --- gcc/cp/call.c | 13 +++++++------ gcc/testsuite/g++.dg/template/conv17.C | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-)
Comments
On 9/20/21 12:46, Patrick Palka wrote: > During operator overload resolution, we currently consider non-member > candidates before built-in candidates. This didn't make a difference > before r12-3346, but after this change add_candidates will avoid > computing excess argument conversions if we've already seen a strictly > viable candidate, so it's better to consider built-in candidates first. Doesn't r12-3346 stop considering conversions after it sees a bad one, and later return to the bad candidate if there is no strictly viable candidate? How does this patch change that? Depending on the order of the candidates seems fragile. > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk? > > gcc/cp/ChangeLog: > > * call.c (add_operator_candidates): Consider built-in operator > candidates before considering non-member candidates. > > gcc/testsuite/ChangeLog: > > * g++.dg/template/conv17.C: Extend test. > --- > gcc/cp/call.c | 13 +++++++------ > gcc/testsuite/g++.dg/template/conv17.C | 7 +++++++ > 2 files changed, 14 insertions(+), 6 deletions(-) > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > index c5601d96ab8..c0da083758f 100644 > --- a/gcc/cp/call.c > +++ b/gcc/cp/call.c > @@ -6321,7 +6321,6 @@ add_operator_candidates (z_candidate **candidates, > vec<tree, va_gc> *arglist, > int flags, tsubst_flags_t complain) > { > - z_candidate *start_candidates = *candidates; > bool ismodop = code2 != ERROR_MARK; > tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code); > > @@ -6333,6 +6332,12 @@ add_operator_candidates (z_candidate **candidates, > if (rewritten && code != EQ_EXPR && code != SPACESHIP_EXPR) > flags &= ~LOOKUP_REWRITTEN; > > + /* Add built-in candidates to the candidate set. The standard says to > + rewrite built-in candidates, too, but there's no point. */ > + if (!rewritten) > + add_builtin_candidates (candidates, code, code2, fnname, arglist, > + flags, complain); > + > bool memonly = false; > switch (code) > { > @@ -6352,6 +6357,7 @@ add_operator_candidates (z_candidate **candidates, > > /* Add namespace-scope operators to the list of functions to > consider. */ > + z_candidate *start_candidates = *candidates; > if (!memonly) > { > tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); > @@ -6423,11 +6429,6 @@ add_operator_candidates (z_candidate **candidates, > > if (!rewritten) > { > - /* The standard says to rewrite built-in candidates, too, > - but there's no point. */ > - add_builtin_candidates (candidates, code, code2, fnname, arglist, > - flags, complain); > - > /* Maybe add C++20 rewritten comparison candidates. */ > tree_code rewrite_code = ERROR_MARK; > if (cxx_dialect >= cxx20 > diff --git a/gcc/testsuite/g++.dg/template/conv17.C b/gcc/testsuite/g++.dg/template/conv17.C > index f0f10f2ef4f..87ecefb8de3 100644 > --- a/gcc/testsuite/g++.dg/template/conv17.C > +++ b/gcc/testsuite/g++.dg/template/conv17.C > @@ -61,3 +61,10 @@ concept E = requires { T().h(nullptr); }; > > static_assert(!E<C>); > #endif > + > +// Verify that the strictly viable built-in operator+ candidate precludes > +// us from computing all argument conversions for the below non-strictly > +// viable non-member candidate. > +enum N { n }; > +int operator+(N&, B); > +int f = n + 42; >
On Mon, 20 Sep 2021, Jason Merrill wrote: > On 9/20/21 12:46, Patrick Palka wrote: > > During operator overload resolution, we currently consider non-member > > candidates before built-in candidates. This didn't make a difference > > before r12-3346, but after this change add_candidates will avoid > > computing excess argument conversions if we've already seen a strictly > > viable candidate, so it's better to consider built-in candidates first. > > Doesn't r12-3346 stop considering conversions after it sees a bad one, and > later return to the bad candidate if there is no strictly viable candidate? > How does this patch change that? Yes, but add_candidates also looks for a strictly viable candidate among the already-considered candidates in the 'candidates' list via the line: bool seen_strictly_viable = any_strictly_viable (*candidates); So by considering the built-in candidates first, the subsequent call to add_candidates that considers the non-member functions in will be aware of any (built-in) strictly viable candidate. > > Depending on the order of the candidates seems fragile. Yeah.. :/ I guess in general it'd be better to build up the entire overload set first and then call add_candidates exactly once (which would also make the perfect candidate optimization more consistent/effective). But I'm not sure if we can easily build up such an overload set in this case since built-in candidates are represented and handled differently than non-built-in candidates.. FWIW, although the test case added by this patch is contrived, this opportunity was found in the real world by instrumenting the 'bad_fns' mechanism added by r12-3346 to look for situations where we still end up using it (and thus end up redundantly considering some candidates twice), and this built-in operator situation was the most common in the codebases that I tested (although still quite rare in the codebases that I tested). > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > trunk? > > > > gcc/cp/ChangeLog: > > > > * call.c (add_operator_candidates): Consider built-in operator > > candidates before considering non-member candidates. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/template/conv17.C: Extend test. > > --- > > gcc/cp/call.c | 13 +++++++------ > > gcc/testsuite/g++.dg/template/conv17.C | 7 +++++++ > > 2 files changed, 14 insertions(+), 6 deletions(-) > > > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > > index c5601d96ab8..c0da083758f 100644 > > --- a/gcc/cp/call.c > > +++ b/gcc/cp/call.c > > @@ -6321,7 +6321,6 @@ add_operator_candidates (z_candidate **candidates, > > vec<tree, va_gc> *arglist, > > int flags, tsubst_flags_t complain) > > { > > - z_candidate *start_candidates = *candidates; > > bool ismodop = code2 != ERROR_MARK; > > tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code); > > @@ -6333,6 +6332,12 @@ add_operator_candidates (z_candidate **candidates, > > if (rewritten && code != EQ_EXPR && code != SPACESHIP_EXPR) > > flags &= ~LOOKUP_REWRITTEN; > > + /* Add built-in candidates to the candidate set. The standard says to > > + rewrite built-in candidates, too, but there's no point. */ > > + if (!rewritten) > > + add_builtin_candidates (candidates, code, code2, fnname, arglist, > > + flags, complain); > > + > > bool memonly = false; > > switch (code) > > { > > @@ -6352,6 +6357,7 @@ add_operator_candidates (z_candidate **candidates, > > /* Add namespace-scope operators to the list of functions to > > consider. */ > > + z_candidate *start_candidates = *candidates; > > if (!memonly) > > { > > tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); > > @@ -6423,11 +6429,6 @@ add_operator_candidates (z_candidate **candidates, > > if (!rewritten) > > { > > - /* The standard says to rewrite built-in candidates, too, > > - but there's no point. */ > > - add_builtin_candidates (candidates, code, code2, fnname, arglist, > > - flags, complain); > > - > > /* Maybe add C++20 rewritten comparison candidates. */ > > tree_code rewrite_code = ERROR_MARK; > > if (cxx_dialect >= cxx20 > > diff --git a/gcc/testsuite/g++.dg/template/conv17.C > > b/gcc/testsuite/g++.dg/template/conv17.C > > index f0f10f2ef4f..87ecefb8de3 100644 > > --- a/gcc/testsuite/g++.dg/template/conv17.C > > +++ b/gcc/testsuite/g++.dg/template/conv17.C > > @@ -61,3 +61,10 @@ concept E = requires { T().h(nullptr); }; > > static_assert(!E<C>); > > #endif > > + > > +// Verify that the strictly viable built-in operator+ candidate precludes > > +// us from computing all argument conversions for the below non-strictly > > +// viable non-member candidate. > > +enum N { n }; > > +int operator+(N&, B); > > +int f = n + 42; > > > >
On 9/20/21 15:32, Patrick Palka wrote: > On Mon, 20 Sep 2021, Jason Merrill wrote: > >> On 9/20/21 12:46, Patrick Palka wrote: >>> During operator overload resolution, we currently consider non-member >>> candidates before built-in candidates. This didn't make a difference >>> before r12-3346, but after this change add_candidates will avoid >>> computing excess argument conversions if we've already seen a strictly >>> viable candidate, so it's better to consider built-in candidates first. >> >> Doesn't r12-3346 stop considering conversions after it sees a bad one, and >> later return to the bad candidate if there is no strictly viable candidate? >> How does this patch change that? > > Yes, but add_candidates also looks for a strictly viable candidate among > the already-considered candidates in the 'candidates' list via the line: > > bool seen_strictly_viable = any_strictly_viable (*candidates); > > So by considering the built-in candidates first, the subsequent call to > add_candidates that considers the non-member functions in will be aware > of any (built-in) strictly viable candidate. Ah, I get it, the problem is that the first add_candidates can't see any strictly-viable candidates. >> Depending on the order of the candidates seems fragile. > > Yeah.. :/ I guess in general it'd be better to build up the entire > overload set first and then call add_candidates exactly once (which > would also make the perfect candidate optimization more consistent/effective). > But I'm not sure if we can easily build up such an overload set in this > case since built-in candidates are represented and handled differently > than non-built-in candidates.. Or as another way of getting the same effect, add another possible value of shortcut_bad_convs to mean leave bad candidates incomplete in the candidates list, and then once we're done adding candidates and still don't have a viable one, we can go back and finish processing the bad candidates? Either way, this could also help when there are both member and non-member candidates for the operator. > FWIW, although the test case added by this patch is contrived, this > opportunity was found in the real world by instrumenting the 'bad_fns' > mechanism added by r12-3346 to look for situations where we still end up > using it (and thus end up redundantly considering some candidates twice), > and this built-in operator situation was the most common in the > codebases that I tested (although still quite rare in the codebases that > I tested). >> >>> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for >>> trunk? >>> >>> gcc/cp/ChangeLog: >>> >>> * call.c (add_operator_candidates): Consider built-in operator >>> candidates before considering non-member candidates. >>> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/template/conv17.C: Extend test. >>> --- >>> gcc/cp/call.c | 13 +++++++------ >>> gcc/testsuite/g++.dg/template/conv17.C | 7 +++++++ >>> 2 files changed, 14 insertions(+), 6 deletions(-) >>> >>> diff --git a/gcc/cp/call.c b/gcc/cp/call.c >>> index c5601d96ab8..c0da083758f 100644 >>> --- a/gcc/cp/call.c >>> +++ b/gcc/cp/call.c >>> @@ -6321,7 +6321,6 @@ add_operator_candidates (z_candidate **candidates, >>> vec<tree, va_gc> *arglist, >>> int flags, tsubst_flags_t complain) >>> { >>> - z_candidate *start_candidates = *candidates; >>> bool ismodop = code2 != ERROR_MARK; >>> tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code); >>> @@ -6333,6 +6332,12 @@ add_operator_candidates (z_candidate **candidates, >>> if (rewritten && code != EQ_EXPR && code != SPACESHIP_EXPR) >>> flags &= ~LOOKUP_REWRITTEN; >>> + /* Add built-in candidates to the candidate set. The standard says to >>> + rewrite built-in candidates, too, but there's no point. */ >>> + if (!rewritten) >>> + add_builtin_candidates (candidates, code, code2, fnname, arglist, >>> + flags, complain); >>> + >>> bool memonly = false; >>> switch (code) >>> { >>> @@ -6352,6 +6357,7 @@ add_operator_candidates (z_candidate **candidates, >>> /* Add namespace-scope operators to the list of functions to >>> consider. */ >>> + z_candidate *start_candidates = *candidates; >>> if (!memonly) >>> { >>> tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); >>> @@ -6423,11 +6429,6 @@ add_operator_candidates (z_candidate **candidates, >>> if (!rewritten) >>> { >>> - /* The standard says to rewrite built-in candidates, too, >>> - but there's no point. */ >>> - add_builtin_candidates (candidates, code, code2, fnname, arglist, >>> - flags, complain); >>> - >>> /* Maybe add C++20 rewritten comparison candidates. */ >>> tree_code rewrite_code = ERROR_MARK; >>> if (cxx_dialect >= cxx20 >>> diff --git a/gcc/testsuite/g++.dg/template/conv17.C >>> b/gcc/testsuite/g++.dg/template/conv17.C >>> index f0f10f2ef4f..87ecefb8de3 100644 >>> --- a/gcc/testsuite/g++.dg/template/conv17.C >>> +++ b/gcc/testsuite/g++.dg/template/conv17.C >>> @@ -61,3 +61,10 @@ concept E = requires { T().h(nullptr); }; >>> static_assert(!E<C>); >>> #endif >>> + >>> +// Verify that the strictly viable built-in operator+ candidate precludes >>> +// us from computing all argument conversions for the below non-strictly >>> +// viable non-member candidate. >>> +enum N { n }; >>> +int operator+(N&, B); >>> +int f = n + 42; >>> >> >> >
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c5601d96ab8..c0da083758f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6321,7 +6321,6 @@ add_operator_candidates (z_candidate **candidates, vec<tree, va_gc> *arglist, int flags, tsubst_flags_t complain) { - z_candidate *start_candidates = *candidates; bool ismodop = code2 != ERROR_MARK; tree fnname = ovl_op_identifier (ismodop, ismodop ? code2 : code); @@ -6333,6 +6332,12 @@ add_operator_candidates (z_candidate **candidates, if (rewritten && code != EQ_EXPR && code != SPACESHIP_EXPR) flags &= ~LOOKUP_REWRITTEN; + /* Add built-in candidates to the candidate set. The standard says to + rewrite built-in candidates, too, but there's no point. */ + if (!rewritten) + add_builtin_candidates (candidates, code, code2, fnname, arglist, + flags, complain); + bool memonly = false; switch (code) { @@ -6352,6 +6357,7 @@ add_operator_candidates (z_candidate **candidates, /* Add namespace-scope operators to the list of functions to consider. */ + z_candidate *start_candidates = *candidates; if (!memonly) { tree fns = lookup_name (fnname, LOOK_where::BLOCK_NAMESPACE); @@ -6423,11 +6429,6 @@ add_operator_candidates (z_candidate **candidates, if (!rewritten) { - /* The standard says to rewrite built-in candidates, too, - but there's no point. */ - add_builtin_candidates (candidates, code, code2, fnname, arglist, - flags, complain); - /* Maybe add C++20 rewritten comparison candidates. */ tree_code rewrite_code = ERROR_MARK; if (cxx_dialect >= cxx20 diff --git a/gcc/testsuite/g++.dg/template/conv17.C b/gcc/testsuite/g++.dg/template/conv17.C index f0f10f2ef4f..87ecefb8de3 100644 --- a/gcc/testsuite/g++.dg/template/conv17.C +++ b/gcc/testsuite/g++.dg/template/conv17.C @@ -61,3 +61,10 @@ concept E = requires { T().h(nullptr); }; static_assert(!E<C>); #endif + +// Verify that the strictly viable built-in operator+ candidate precludes +// us from computing all argument conversions for the below non-strictly +// viable non-member candidate. +enum N { n }; +int operator+(N&, B); +int f = n + 42;