On 8/9/24 3:30 PM, Patrick Palka wrote:
On Fri, 9 Aug 2024, Jason Merrill wrote:

On 8/9/24 2:32 PM, Patrick Palka wrote:
On Fri, 9 Aug 2024, Patrick Palka wrote:

On Fri, 9 Aug 2024, Jason Merrill wrote:

On 8/8/24 1:00 PM, Patrick Palka wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
look OK for trunk/14?

-- >8 --

This implements the inherited vs non-inherited guide tiebreaker
specified by P2582R1.  In order to track inherited-ness of a guide
it seems natural to reuse the lang_decl_fn::context field that already
tracks inherited-ness of a constructor.

This patch also works around CLASSTYPE_CONSTRUCTORS apparently not
always containing all inherited constructors, by iterating over
TYPE_FIELDS instead.

This patch also makes us recognize another written form of inherited
constructor, 'using Base<T>::Base::Base' whose USING_DECL_SCOPE is a
TYPENAME_TYPE.

        PR c++/116276

gcc/cp/ChangeLog:

        * call.cc (joust): Implement P2582R1 inherited vs
non-inherited
        guide tiebreaker.
        * cp-tree.h (lang_decl_fn::context): Document usage in
        deduction_guide_p FUNCTION_DECLs.
        (inherited_guide_p): Declare.
        * pt.cc (inherited_guide_p): Define.
        (set_inherited_guide_context): Define.
        (alias_ctad_tweaks): Use set_inherited_guide_context.
        (inherited_ctad_tweaks): Recognize some inherited constructors
        whose scope is a TYPENAME_TYPE.
        (ctor_deduction_guides_for): For C++23 inherited CTAD, loop
        over TYPE_FIELDS instead of using CLASSTYPE_CONSTRUCTORS to
        recognize all relevant using-decls.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp23/class-deduction-inherited4.C: Extend test.
        * g++.dg/cpp23/class-deduction-inherited5.C: New test.
---
    gcc/cp/call.cc                                | 22 +++++++++
    gcc/cp/cp-tree.h                              |  8 +++-
    gcc/cp/pt.cc                                  | 45
+++++++++++++++----
    .../g++.dg/cpp23/class-deduction-inherited4.C | 15 ++++++-
    .../g++.dg/cpp23/class-deduction-inherited5.C | 25 +++++++++++
    5 files changed, 103 insertions(+), 12 deletions(-)
    create mode 100644
gcc/testsuite/g++.dg/cpp23/class-deduction-inherited5.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index a75e2e5e3af..3287f77b59b 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13261,6 +13261,28 @@ joust (struct z_candidate *cand1, struct
z_candidate *cand2, bool warn,
      else if (cand2->rewritten ())
        return 1;
    +  /* F1 and F2 are generated from class template argument
deduction for a
class
+     D, and F2 is generated from inheriting constructors from a base
class
of D
+     while F1 is not, and for each explicit function argument, the
corresponding
+     parameters of F1 and F2 are either both ellipses or have the
same type
*/
+  if (deduction_guide_p (cand1->fn))
+    {
+      bool inherited1 = inherited_guide_p (cand1->fn);
+      bool inherited2 = inherited_guide_p (cand2->fn);
+      if (int diff = inherited2 - inherited1)
+       {
+         for (i = 0; i < len; ++i)
+           {
+             conversion *t1 = cand1->convs[i + off1];
+             conversion *t2 = cand2->convs[i + off2];
+             if (!same_type_p (t1->type, t2->type))

I'm not sure this comparison distinguishes between ellipse and
non-ellipse?
There doesn't seem to be a testcase for that.

Unfortunately I haven't been able to come up with a testcase for
the ellipses logic :/  It seems the earlier ICS comparison would always
break the tie first if one parameter is an ellipsis but not the other?

Just mention that in a comment, then.

Is there a known example that perhaps motivated the wording?

I'm failing to find anything, it appeared between R0 and R1 without a
corresponding comment on the wiki.

Relatidely I noticed that unlike the inherited guide tiebreaker, the
inherited ctor tiebreaker doesn't mention ellipses, which seems
surprising: https://eel.is/c++draft/over.match.best#general-2.7

Here's v2 which is just a tidied up version of v1 along with an extra
test (no additional functional change):

-- >8 --

Subject: [PATCH] c++: inherited CTAD fixes [PR116276]

This implements the overlooked inherited vs non-inherited guide
tiebreaker from P2582R1.  In order to track inherited-ness of a guide
it seems natural to reuse the lang_decl_fn::context field which also
tracks inherited-ness of a constructor.

This patch also works around CLASSTYPE_CONSTRUCTORS not reliably
returning all inherited constructors, by iterating over TYPE_FIELDS
instead.

Did you investigate why that is?

For e.g.

     template<class T>
     struct B { };

     template<class T>
     struct A : B<T> {
       A();           // target_bval
       using B<T>::B; // decl
     };

it's because of an early exit in push_class_level_binding:

       else if (TREE_CODE (decl) == USING_DECL
                && DECL_DEPENDENT_P (decl)
                && OVL_P (target_bval))
         /* The new dependent using beats an old overload.  */
         old_decl = bval;

       ...

       if (old_decl && binding->scope == class_binding_level)
         {
           binding->value = x;
           /* It is always safe to clear INHERITED_VALUE_BINDING_P
              here.  This function is only used to register bindings
              from with the class definition itself.  */
           INHERITED_VALUE_BINDING_P (binding) = 0;
           return true;
         }

and so we don't call supplement_binding which seems to be what's
responsible for augmenting the binding properly.  After the early
exit, CLASSTYPE_CONSTRUCTORS still returns only A().

Note that if we swap the order of the two member declarations above
then CLASSTYPE_CONSTRUCTORS at the end will return only the using.
So the result of name lookup in this case is sensitive to member
declaration order which seems like a bug.

I'm afraid I don't understand the name lookup code enough to
fix this issue..

Ah, right, that mess; we certainly aren't going to clean that up for this PR. So the patch is OK with the ellipsis comment I mentioned.

Jason

Reply via email to