diff options
author | Jason Merrill <jason@redhat.com> | 2023-03-03 15:04:25 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2023-06-14 10:03:09 -0400 |
commit | 4ec6b627cb008e31ea3d1ee93a209297f56c6a3e (patch) | |
tree | 58b23f334e82e421105a21051d6253cfa3b15a0d /gcc | |
parent | 29aef9ff236022ebf566738f9bd08bb5e28fe6ca (diff) | |
download | gcc-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.cc | 56 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/overload-conv-4.C | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/elide7.C | 14 |
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{}); |