aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2023-03-03 15:04:25 -0500
committerJason Merrill <jason@redhat.com>2023-06-14 10:03:09 -0400
commit4ec6b627cb008e31ea3d1ee93a209297f56c6a3e (patch)
tree58b23f334e82e421105a21051d6253cfa3b15a0d /gcc
parent29aef9ff236022ebf566738f9bd08bb5e28fe6ca (diff)
downloadgcc-4ec6b627cb008e31ea3d1ee93a209297f56c6a3e.zip
gcc-4ec6b627cb008e31ea3d1ee93a209297f56c6a3e.tar.gz
gcc-4ec6b627cb008e31ea3d1ee93a209297f56c6a3e.tar.bz2
c++: tweak c++17 ctor/conversion tiebreaker [DR2327]
In discussion of this issue CWG decided that the change of behavior on well-formed code like overload-conv-4.C is undesirable. In further discussion of possible resolutions, we discovered that we can avoid that change while still getting the desired behavior on overload-conv-3.C by making this a tiebreaker after comparing conversions, rather than before. This also simplifies the implementation. The issue resolution has not yet been finalized, but this seems like a clear improvement. DR 2327 PR c++/86521 gcc/cp/ChangeLog: * call.cc (joust_maybe_elide_copy): Don't change cand. (joust): Move the elided tiebreaker later. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/overload-conv-4.C: Remove warnings. * g++.dg/cpp1z/elide7.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/call.cc56
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/elide7.C14
3 files changed, 39 insertions, 36 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 68cf878..15a3d6f 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -12560,11 +12560,11 @@ add_warning (struct z_candidate *winner, struct z_candidate *loser)
}
/* CAND is a constructor candidate in joust in C++17 and up. If it copies a
- prvalue returned from a conversion function, replace CAND with the candidate
- for the conversion and return true. Otherwise, return false. */
+ prvalue returned from a conversion function, return true. Otherwise, return
+ false. */
static bool
-joust_maybe_elide_copy (z_candidate *&cand)
+joust_maybe_elide_copy (z_candidate *cand)
{
tree fn = cand->fn;
if (!DECL_COPY_CONSTRUCTOR_P (fn) && !DECL_MOVE_CONSTRUCTOR_P (fn))
@@ -12580,10 +12580,7 @@ joust_maybe_elide_copy (z_candidate *&cand)
(conv->type, DECL_CONTEXT (fn)));
z_candidate *uc = conv->cand;
if (DECL_CONV_FN_P (uc->fn))
- {
- cand = uc;
- return true;
- }
+ return true;
}
return false;
}
@@ -12735,27 +12732,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
}
}
- /* Handle C++17 copy elision in [over.match.ctor] (direct-init) context. The
- standard currently says that only constructors are candidates, but if one
- copies a prvalue returned by a conversion function we want to treat the
- conversion as the candidate instead.
-
- Clang does something similar, as discussed at
- http://lists.isocpp.org/core/2017/10/3166.php
- http://lists.isocpp.org/core/2019/03/5721.php */
- int elided_tiebreaker = 0;
- if (len == 1 && cxx_dialect >= cxx17
- && DECL_P (cand1->fn)
- && DECL_COMPLETE_CONSTRUCTOR_P (cand1->fn)
- && !(cand1->flags & LOOKUP_ONLYCONVERTING))
- {
- bool elided1 = joust_maybe_elide_copy (cand1);
- bool elided2 = joust_maybe_elide_copy (cand2);
- /* As a tiebreaker below we will prefer a constructor to a conversion
- operator exposed this way. */
- elided_tiebreaker = elided2 - elided1;
- }
-
for (i = 0; i < len; ++i)
{
conversion *t1 = cand1->convs[i + off1];
@@ -12917,11 +12893,6 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
if (winner)
return winner;
- /* Put this tiebreaker first, so that we don't try to look at second_conv of
- a constructor candidate that doesn't have one. */
- if (elided_tiebreaker)
- return elided_tiebreaker;
-
/* DR 495 moved this tiebreaker above the template ones. */
/* or, if not that,
the context is an initialization by user-defined conversion (see
@@ -12958,6 +12929,25 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
}
}
+ /* DR2327: C++17 copy elision in [over.match.ctor] (direct-init) context.
+ The standard currently says that only constructors are candidates, but if
+ one copies a prvalue returned by a conversion function we prefer that.
+
+ Clang does something similar, as discussed at
+ http://lists.isocpp.org/core/2017/10/3166.php
+ http://lists.isocpp.org/core/2019/03/5721.php */
+ if (len == 1 && cxx_dialect >= cxx17
+ && DECL_P (cand1->fn)
+ && DECL_COMPLETE_CONSTRUCTOR_P (cand1->fn)
+ && !(cand1->flags & LOOKUP_ONLYCONVERTING))
+ {
+ bool elided1 = joust_maybe_elide_copy (cand1);
+ bool elided2 = joust_maybe_elide_copy (cand2);
+ winner = elided1 - elided2;
+ if (winner)
+ return winner;
+ }
+
/* or, if not that,
F1 is a non-template function and F2 is a template function
specialization. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C b/gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C
index 6fcdbba..d2663e6 100644
--- a/gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C
@@ -17,7 +17,6 @@ B
f (A x)
{
// C++14: we call B::B(A const &)
- // C++17: we call A::operator B()
- return B(x); // { dg-warning "choosing .A::operator B\\(\\). over .B::B\\(const A&\\)" "" { target c++17 } }
- // { dg-warning "for conversion from .A. to .B." "" { target c++17 } .-1 }
+ // C++17: now the same
+ return B(x);
}
diff --git a/gcc/testsuite/g++.dg/cpp1z/elide7.C b/gcc/testsuite/g++.dg/cpp1z/elide7.C
new file mode 100644
index 0000000..2d8cc65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/elide7.C
@@ -0,0 +1,14 @@
+// DR2327: In direct-initialization, prefer a constructor even if it requires a
+// qualification conversion.
+
+// { dg-do compile { target c++11 } }
+
+struct Dog;
+struct Cat {
+ Cat(const Dog&);
+};
+struct Dog {
+ operator Cat() = delete;
+};
+
+Cat cat(Dog{});