c++: reference list-init, conversion fn [PR113141]
The original testcase in PR113141 is an instance of CWG1996; the standard fails to consider conversion functions when initializing a reference directly from an initializer-list of one element, but then does consider them when initializing a temporary. I have a proposed fix for this defect, which is implemented here. DR 1996 PR c++/113141 gcc/cp/ChangeLog: * call.cc (reference_binding): Check direct binding from a single-element list. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/initlist-ref1.C: New test. * g++.dg/cpp0x/initlist-ref2.C: New test. * g++.dg/cpp0x/initlist-ref3.C: New test. Co-authored-by: Patrick Palka <ppalka@redhat.com>
This commit is contained in:
parent
c950008307
commit
d435571b54
4 changed files with 56 additions and 4 deletions
|
@ -1596,7 +1596,9 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
return conv;
|
||||
}
|
||||
|
||||
/* Returns nonzero if T1 is reference-related to T2. */
|
||||
/* Returns nonzero if T1 is reference-related to T2.
|
||||
|
||||
This is considered when a reference to T1 is initialized by a T2. */
|
||||
|
||||
bool
|
||||
reference_related_p (tree t1, tree t2)
|
||||
|
@ -1757,6 +1759,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|||
}
|
||||
|
||||
bool copy_list_init = false;
|
||||
bool single_list_conv = false;
|
||||
if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
|
||||
{
|
||||
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
|
||||
|
@ -1783,6 +1786,11 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|||
from = etype;
|
||||
goto skip;
|
||||
}
|
||||
else if (CLASS_TYPE_P (etype) && TYPE_HAS_CONVERSION (etype))
|
||||
/* CWG1996: jason's proposed drafting adds "or initializing T from E
|
||||
would bind directly". We check that in the direct binding with
|
||||
conversion code below. */
|
||||
single_list_conv = true;
|
||||
}
|
||||
/* Otherwise, if T is a reference type, a prvalue temporary of the type
|
||||
referenced by T is copy-list-initialized, and the reference is bound
|
||||
|
@ -1907,9 +1915,14 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|||
(possibly cv-qualified) object to the (possibly cv-qualified) same
|
||||
object type (or a reference to it), to a (possibly cv-qualified) base
|
||||
class of that type (or a reference to it).... */
|
||||
else if (CLASS_TYPE_P (from) && !related_p
|
||||
&& !(flags & LOOKUP_NO_CONVERSION))
|
||||
else if (!related_p
|
||||
&& !(flags & LOOKUP_NO_CONVERSION)
|
||||
&& (CLASS_TYPE_P (from) || single_list_conv))
|
||||
{
|
||||
tree rexpr = expr;
|
||||
if (single_list_conv)
|
||||
rexpr = CONSTRUCTOR_ELT (expr, 0)->value;
|
||||
|
||||
/* [dcl.init.ref]
|
||||
|
||||
If the initializer expression
|
||||
|
@ -1923,7 +1936,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
|
|||
|
||||
the reference is bound to the lvalue result of the conversion
|
||||
in the second case. */
|
||||
z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
|
||||
z_candidate *cand = build_user_type_conversion_1 (rto, rexpr, flags,
|
||||
complain);
|
||||
if (cand)
|
||||
{
|
||||
|
|
16
gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
Normal file
16
gcc/testsuite/g++.dg/cpp0x/initlist-ref1.C
Normal file
|
@ -0,0 +1,16 @@
|
|||
// PR c++/113141
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct ConvToRef {
|
||||
operator int&();
|
||||
};
|
||||
|
||||
struct A { int& r; };
|
||||
|
||||
void f(A);
|
||||
|
||||
int main() {
|
||||
ConvToRef c;
|
||||
A a{{c}};
|
||||
f({{c}});
|
||||
}
|
10
gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C
Normal file
10
gcc/testsuite/g++.dg/cpp0x/initlist-ref2.C
Normal file
|
@ -0,0 +1,10 @@
|
|||
// CWG1996
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct S { operator struct D &(); } s;
|
||||
D &d{s}; // OK, direct binding
|
||||
|
||||
namespace N1 {
|
||||
struct S { operator volatile struct D &(); } s;
|
||||
const D &dr{s}; // { dg-error "invalid user-defined|discards qualifiers" }
|
||||
}
|
13
gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C
Normal file
13
gcc/testsuite/g++.dg/cpp0x/initlist-ref3.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// CWG1996
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct D { constexpr D() {} } d;
|
||||
struct S {
|
||||
template <class T>
|
||||
constexpr operator T& () const { return d; }
|
||||
};
|
||||
constexpr S s;
|
||||
constexpr const D &dr1(s);
|
||||
static_assert (&dr1 == &d, "");
|
||||
constexpr const D &dr2{s};
|
||||
static_assert (&dr2 == &d, "");
|
Loading…
Add table
Reference in a new issue