mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
c++: bad direct reference binding via conv fn [PR113064]
When computing a direct reference binding via a conversion function yields a bad conversion, reference_binding incorrectly commits to that conversion instead of trying a conversion via a temporary. This causes us to reject the first testcase because the bad direct conversion to B&& via the && conversion operator prevents us from considering the good conversion via the & conversion operator and a temporary. (Similar story for the second testcase.) This patch fixes this by making reference_binding not prematurely commit to such a bad direct conversion. We still fall back to it if using a temporary also fails (otherwise the diagnostic for cpp0x/explicit7.C regresses). PR c++/113064 gcc/cp/ChangeLog: * call.cc (reference_binding): Still try a conversion via a temporary if a direct conversion was bad. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/rv-conv4.C: New test. * g++.dg/cpp0x/rv-conv5.C: New test.
This commit is contained in:
@@ -1739,6 +1739,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
tsubst_flags_t complain)
|
||||
{
|
||||
conversion *conv = NULL;
|
||||
conversion *bad_direct_conv = nullptr;
|
||||
tree to = TREE_TYPE (rto);
|
||||
tree from = rfrom;
|
||||
tree tfrom;
|
||||
@@ -1925,13 +1926,23 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
|
||||
complain);
|
||||
if (cand)
|
||||
return cand->second_conv;
|
||||
{
|
||||
if (!cand->second_conv->bad_p)
|
||||
return cand->second_conv;
|
||||
|
||||
/* Direct reference binding wasn't successful and yielded a bad
|
||||
conversion. Proceed with trying to go through a temporary
|
||||
instead, and if that also fails then we'll return this bad
|
||||
conversion rather than no conversion for sake of better
|
||||
diagnostics. */
|
||||
bad_direct_conv = cand->second_conv;
|
||||
}
|
||||
}
|
||||
|
||||
/* From this point on, we conceptually need temporaries, even if we
|
||||
elide them. Only the cases above are "direct bindings". */
|
||||
if (flags & LOOKUP_NO_TEMP_BIND)
|
||||
return NULL;
|
||||
return bad_direct_conv ? bad_direct_conv : nullptr;
|
||||
|
||||
/* [over.ics.rank]
|
||||
|
||||
@@ -1972,6 +1983,9 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
there's no strictly viable candidate. */
|
||||
if (!maybe_valid_p && (flags & LOOKUP_SHORTCUT_BAD_CONVS))
|
||||
{
|
||||
if (bad_direct_conv)
|
||||
return bad_direct_conv;
|
||||
|
||||
conv = alloc_conversion (ck_deferred_bad);
|
||||
conv->bad_p = true;
|
||||
return conv;
|
||||
@@ -1995,7 +2009,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
conv = implicit_conversion (to, from, expr, c_cast_p,
|
||||
flags, complain);
|
||||
if (!conv)
|
||||
return NULL;
|
||||
return bad_direct_conv ? bad_direct_conv : nullptr;
|
||||
|
||||
if (conv->user_conv_p)
|
||||
{
|
||||
@@ -2018,7 +2032,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
||||
= reference_binding (rto, ftype, NULL_TREE, c_cast_p,
|
||||
sflags, complain);
|
||||
if (!new_second)
|
||||
return NULL;
|
||||
return bad_direct_conv ? bad_direct_conv : nullptr;
|
||||
conv = merge_conversion_sequences (t, new_second);
|
||||
gcc_assert (maybe_valid_p || conv->bad_p);
|
||||
return conv;
|
||||
|
||||
16
gcc/testsuite/g++.dg/cpp0x/rv-conv4.C
Normal file
16
gcc/testsuite/g++.dg/cpp0x/rv-conv4.C
Normal file
@@ -0,0 +1,16 @@
|
||||
// PR c++/113064
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct B { };
|
||||
|
||||
struct A {
|
||||
operator B() &;
|
||||
operator B&&() &&;
|
||||
};
|
||||
|
||||
void f(B&&);
|
||||
|
||||
int main() {
|
||||
A a;
|
||||
f(a);
|
||||
}
|
||||
23
gcc/testsuite/g++.dg/cpp0x/rv-conv5.C
Normal file
23
gcc/testsuite/g++.dg/cpp0x/rv-conv5.C
Normal file
@@ -0,0 +1,23 @@
|
||||
// PR c++/113064
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct no_copy {
|
||||
no_copy() = default;
|
||||
|
||||
no_copy(const no_copy&) = delete;
|
||||
no_copy(no_copy&&);
|
||||
|
||||
no_copy& operator=(const no_copy&) = delete;
|
||||
no_copy& operator=(no_copy&&);
|
||||
};
|
||||
|
||||
struct A {
|
||||
operator no_copy() &;
|
||||
operator no_copy&&() && = delete;
|
||||
};
|
||||
|
||||
int main() {
|
||||
no_copy nc;
|
||||
A a;
|
||||
nc = a;
|
||||
}
|
||||
Reference in New Issue
Block a user