diff options
author | Marek Polacek <polacek@redhat.com> | 2020-04-22 20:12:47 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-04-26 21:08:41 -0400 |
commit | feb801f62239528bca2cfb6c3abd70d434b69c0a (patch) | |
tree | e5b98b248b797bf5a63855496422ea0c647d4708 | |
parent | c80863570664e7754ba1a4b8c1df6a19b2589920 (diff) | |
download | gcc-feb801f62239528bca2cfb6c3abd70d434b69c0a.zip gcc-feb801f62239528bca2cfb6c3abd70d434b69c0a.tar.gz gcc-feb801f62239528bca2cfb6c3abd70d434b69c0a.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/call.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/explicit13.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/explicit14.C | 16 |
5 files changed, 66 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 32408f7..4e0ea91 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c582316..8345997 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/ChangeLog b/gcc/testsuite/ChangeLog index d6529ea..1e33258 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit13.C b/gcc/testsuite/g++.dg/cpp0x/explicit13.C new file mode 100644 index 0000000..cbd9a73 --- /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 0000000..8a8adfe --- /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; |