On 4/26/20 2:00 PM, Marek Polacek wrote:
On Fri, Apr 24, 2020 at 04:07:03PM -0400, Jason Merrill via Gcc-patches wrote:
On 4/23/20 7:08 PM, Marek Polacek wrote:
@@ -1252,6 +1252,8 @@ 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 (flags & LOOKUP_ONLYCONVERTING)
+ conv->need_temporary_p = true;
Presumably we want the same thing for ck_base?
We actually already set need_temporary_p for ck_base in standard_conversion:
1529 conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND);
Hmm, yes. So with your patch the flag means different things for ck_base
and ck_rvalue. This suggests to me that overloading need_temporary_p to
also indicate copy-initialization is problematic, and we should move that
information to a new flag.
OK, done in the following. I think the new flag might be useful for PR87605
too.
That sounds plausible. Going forward I think we want to use it for
ck_ambig and ck_user as well.
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK, thanks.
-- >8 --
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.
---
gcc/cp/call.c | 26 ++++++++++++++++++++-----
gcc/testsuite/g++.dg/cpp0x/explicit13.C | 14 +++++++++++++
gcc/testsuite/g++.dg/cpp0x/explicit14.C | 16 +++++++++++++++
3 files changed, 51 insertions(+), 5 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/explicit13.C
create mode 100644 gcc/testsuite/g++.dg/cpp0x/explicit14.C
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c58231601c9..8345997ccf9 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit13.C
b/gcc/testsuite/g++.dg/cpp0x/explicit13.C
new file mode 100644
index 00000000000..cbd9a73d8fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit13.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit14.C
b/gcc/testsuite/g++.dg/cpp0x/explicit14.C
new file mode 100644
index 00000000000..8a8adfe1677
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit14.C
@@ -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;
base-commit: 870923cd48e1e715120ff68425437e5b346283a1