c++: Explicit constructor called in copy-initialization [PR90320]
This test is rejected with a bogus "use of deleted function" error starting with r225705 whereby convert_like_real/ck_base no longer sets LOOKUP_ONLYCONVERTING for user_conv_p conversions. This does not seem to be always correct. To recap, when we have something like T t = x where T is a class type and the type of x is not T or derived from T, we perform copy-initialization, something like: 1. choose a user-defined conversion to convert x to T, the result is a prvalue, 2. use this prvalue to direct-initialize t. In the second step, explicit constructors should be considered, since we're direct-initializing. This is what r225705 fixed. In this PR we are dealing with the first step, I think, where explicit constructors should be skipped. [over.match.copy] says "The converting constructors of T are candidate functions" which clearly eliminates explicit constructors. But we also have to copy-initialize the argument we are passing to such a converting constructor, and here we should disregard explicit constructors too. In this testcase we have V v = m; and we choose V::V(M) to convert m to V. But we wrongly choose the explicit M::M<M&>(M&) to copy-initialize the argument; it's a better match for a non-const lvalue than the implicit M::M(const M&) but because it's explicit, we shouldn't use it. When convert_like is processing the ck_user conversion -- the convfn is V::V(M) -- it can see that cand->flags contains LOOKUP_ONLYCONVERTING, but then when we're in build_over_call for this convfn, we have no way to pass the flag to convert_like for the argument 'm', because convert_like doesn't take flags. Fixed by creating a new conversion flag, copy_init_p, set in ck_base/ck_rvalue to signal that explicit constructors should be skipped. LOOKUP_COPY_PARM looks relevant, but again, it's a LOOKUP_* flag, so can't pass it to convert_like. DR 899 also seemed related, but that deals with direct-init contexts only. PR c++/90320 * call.c (struct conversion): Add copy_init_p. (standard_conversion): Set copy_init_p in ck_base and ck_rvalue if FLAGS demands LOOKUP_ONLYCONVERTING. (convert_like_real) <case ck_base>: If copy_init_p is set, or LOOKUP_ONLYCONVERTING into FLAGS. * g++.dg/cpp0x/explicit13.C: New test. * g++.dg/cpp0x/explicit14.C: New test.
This commit is contained in:
parent
c808635706
commit
feb801f622
5 changed files with 66 additions and 5 deletions
|
@ -1,3 +1,12 @@
|
|||
2020-04-22 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/90320
|
||||
* call.c (struct conversion): Add copy_init_p.
|
||||
(standard_conversion): Set copy_init_p in ck_base and ck_rvalue
|
||||
if FLAGS demands LOOKUP_ONLYCONVERTING.
|
||||
(convert_like_real) <case ck_base>: If copy_init_p is set, or
|
||||
LOOKUP_ONLYCONVERTING into FLAGS.
|
||||
|
||||
2020-04-26 Iain Sandoe <iain@sandoe.co.uk>
|
||||
|
||||
PR c++/94752
|
||||
|
|
|
@ -92,7 +92,7 @@ struct conversion {
|
|||
language standards, e.g. disregarding pointer qualifiers or
|
||||
converting integers to pointers. */
|
||||
BOOL_BITFIELD bad_p : 1;
|
||||
/* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
|
||||
/* If KIND is ck_ref_bind or ck_base, true to indicate that a
|
||||
temporary should be created to hold the result of the
|
||||
conversion. If KIND is ck_ambig or ck_user, true means force
|
||||
copy-initialization. */
|
||||
|
@ -111,6 +111,10 @@ struct conversion {
|
|||
/* Whether check_narrowing should only check TREE_CONSTANTs; used
|
||||
in build_converted_constant_expr. */
|
||||
BOOL_BITFIELD check_narrowing_const_only: 1;
|
||||
/* True if this conversion is taking place in a copy-initialization context
|
||||
and we should only consider converting constructors. Only set in
|
||||
ck_base and ck_rvalue. */
|
||||
BOOL_BITFIELD copy_init_p : 1;
|
||||
/* The type of the expression resulting from the conversion. */
|
||||
tree type;
|
||||
union {
|
||||
|
@ -1252,6 +1256,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
if (flags & LOOKUP_PREFER_RVALUE)
|
||||
/* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */
|
||||
conv->rvaluedness_matches_p = true;
|
||||
/* If we're performing copy-initialization, remember to skip
|
||||
explicit constructors. */
|
||||
if (flags & LOOKUP_ONLYCONVERTING)
|
||||
conv->copy_init_p = true;
|
||||
}
|
||||
|
||||
/* Allow conversion between `__complex__' data types. */
|
||||
|
@ -1528,6 +1536,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
|
|||
if (flags & LOOKUP_PREFER_RVALUE)
|
||||
/* Tell convert_like_real to set LOOKUP_PREFER_RVALUE. */
|
||||
conv->rvaluedness_matches_p = true;
|
||||
/* If we're performing copy-initialization, remember to skip
|
||||
explicit constructors. */
|
||||
if (flags & LOOKUP_ONLYCONVERTING)
|
||||
conv->copy_init_p = true;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
@ -7653,12 +7665,16 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
|||
type is the same class as, or a derived class of, the class of the
|
||||
destination [is treated as direct-initialization]. [dcl.init] */
|
||||
flags = LOOKUP_NORMAL;
|
||||
/* This conversion is being done in the context of a user-defined
|
||||
conversion (i.e. the second step of copy-initialization), so
|
||||
don't allow any more. */
|
||||
if (convs->user_conv_p)
|
||||
/* This conversion is being done in the context of a user-defined
|
||||
conversion (i.e. the second step of copy-initialization), so
|
||||
don't allow any more. */
|
||||
flags |= LOOKUP_NO_CONVERSION;
|
||||
else
|
||||
/* We might be performing a conversion of the argument
|
||||
to the user-defined conversion, i.e., not a conversion of the
|
||||
result of the user-defined conversion. In which case we skip
|
||||
explicit constructors. */
|
||||
if (convs->copy_init_p)
|
||||
flags |= LOOKUP_ONLYCONVERTING;
|
||||
if (convs->rvaluedness_matches_p)
|
||||
/* standard_conversion got LOOKUP_PREFER_RVALUE. */
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2020-04-22 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/90320
|
||||
* g++.dg/cpp0x/explicit13.C: New test.
|
||||
* g++.dg/cpp0x/explicit14.C: New test.
|
||||
|
||||
2020-04-27 Iain Buclaw <ibuclaw@gdcproject.org>
|
||||
|
||||
PR d/89418
|
||||
|
|
14
gcc/testsuite/g++.dg/cpp0x/explicit13.C
Normal file
14
gcc/testsuite/g++.dg/cpp0x/explicit13.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// PR c++/90320
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct M {
|
||||
M() = default;
|
||||
template <typename T> explicit M(T&&) = delete;
|
||||
};
|
||||
|
||||
struct V {
|
||||
V(M m);
|
||||
};
|
||||
|
||||
M m;
|
||||
V v = m;
|
16
gcc/testsuite/g++.dg/cpp0x/explicit14.C
Normal file
16
gcc/testsuite/g++.dg/cpp0x/explicit14.C
Normal file
|
@ -0,0 +1,16 @@
|
|||
// PR c++/90320
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct B { };
|
||||
|
||||
struct M : B {
|
||||
M() = default;
|
||||
template <typename T> explicit M(T&&) = delete;
|
||||
};
|
||||
|
||||
struct V {
|
||||
V(B);
|
||||
};
|
||||
|
||||
M m;
|
||||
V v = m;
|
Loading…
Add table
Reference in a new issue