Commit 2170d4b6 by Jason Merrill Committed by Jason Merrill

PR c++/81311 - wrong C++17 overload resolution.

	* call.c (build_user_type_conversion_1): Remove C++17 code.
	(conv_binds_ref_to_prvalue): New.
	(build_over_call): Handle C++17 copy elision.
	(build_special_member_call): Only do C++17 copy elision here if the
	argument is already the right type.

From-SVN: r258755
parent a0e46153
2018-03-21 Jason Merrill <jason@redhat.com>
PR c++/81311 - wrong C++17 overload resolution.
* call.c (build_user_type_conversion_1): Remove C++17 code.
(conv_binds_ref_to_prvalue): New.
(build_over_call): Handle C++17 copy elision.
(build_special_member_call): Only do C++17 copy elision here if the
argument is already the right type.
2018-03-21 Alexandre Oliva <aoliva@redhat.com> 2018-03-21 Alexandre Oliva <aoliva@redhat.com>
PR c++/71965 PR c++/71965
......
...@@ -3748,14 +3748,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, ...@@ -3748,14 +3748,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
creating a garbage BASELINK; constructors can't be inherited. */ creating a garbage BASELINK; constructors can't be inherited. */
ctors = get_class_binding (totype, complete_ctor_identifier); ctors = get_class_binding (totype, complete_ctor_identifier);
/* FIXME P0135 doesn't say what to do in C++17 about list-initialization from
a single element. For now, let's handle constructors as before and also
consider conversion operators from the element. */
if (cxx_dialect >= cxx17
&& BRACE_ENCLOSED_INITIALIZER_P (expr)
&& CONSTRUCTOR_NELTS (expr) == 1)
fromtype = TREE_TYPE (CONSTRUCTOR_ELT (expr, 0)->value);
if (MAYBE_CLASS_TYPE_P (fromtype)) if (MAYBE_CLASS_TYPE_P (fromtype))
{ {
tree to_nonref = non_reference (totype); tree to_nonref = non_reference (totype);
...@@ -3832,7 +3824,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, ...@@ -3832,7 +3824,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags,
if (conv_fns) if (conv_fns)
{ {
if (BRACE_ENCLOSED_INITIALIZER_P (expr)) if (BRACE_ENCLOSED_INITIALIZER_P (expr))
/* FIXME see above about C++17. */
first_arg = CONSTRUCTOR_ELT (expr, 0)->value; first_arg = CONSTRUCTOR_ELT (expr, 0)->value;
else else
first_arg = expr; first_arg = expr;
...@@ -7604,6 +7595,26 @@ unsafe_copy_elision_p (tree target, tree exp) ...@@ -7604,6 +7595,26 @@ unsafe_copy_elision_p (tree target, tree exp)
&& !AGGR_INIT_VIA_CTOR_P (init)); && !AGGR_INIT_VIA_CTOR_P (init));
} }
/* True iff C is a conversion that binds a reference to a prvalue. */
static bool
conv_binds_ref_to_prvalue (conversion *c)
{
if (c->kind != ck_ref_bind)
return false;
if (c->need_temporary_p)
return true;
c = next_conversion (c);
if (c->kind == ck_rvalue)
return true;
if (c->kind == ck_user && TREE_CODE (c->type) != REFERENCE_TYPE)
return true;
return false;
}
/* Subroutine of the various build_*_call functions. Overload resolution /* Subroutine of the various build_*_call functions. Overload resolution
has chosen a winning candidate CAND; build up a CALL_EXPR accordingly. has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a
...@@ -7682,6 +7693,22 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -7682,6 +7693,22 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
joust (cand, w->loser, 1, complain); joust (cand, w->loser, 1, complain);
} }
/* Core issue 2327: P0135 doesn't say how to handle the case where the
argument to the copy constructor ends up being a prvalue after
conversion. Let's do the normal processing, but pretend we aren't
actually using the copy constructor. */
bool force_elide = false;
if (cxx_dialect >= cxx17
&& cand->num_convs == 1
&& DECL_COMPLETE_CONSTRUCTOR_P (fn)
&& (DECL_COPY_CONSTRUCTOR_P (fn)
|| DECL_MOVE_CONSTRUCTOR_P (fn))
&& conv_binds_ref_to_prvalue (convs[0]))
{
force_elide = true;
goto not_really_used;
}
/* OK, we're actually calling this inherited constructor; set its deletedness /* OK, we're actually calling this inherited constructor; set its deletedness
appropriately. We can get away with doing this here because calling is appropriately. We can get away with doing this here because calling is
the only way to refer to a constructor. */ the only way to refer to a constructor. */
...@@ -7746,6 +7773,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -7746,6 +7773,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
/* else continue to get conversion error. */ /* else continue to get conversion error. */
} }
not_really_used:
/* N3276 magic doesn't apply to nested calls. */ /* N3276 magic doesn't apply to nested calls. */
tsubst_flags_t decltype_flag = (complain & tf_decltype); tsubst_flags_t decltype_flag = (complain & tf_decltype);
complain &= ~tf_decltype; complain &= ~tf_decltype;
...@@ -8066,7 +8095,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -8066,7 +8095,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
/* Avoid actually calling copy constructors and copy assignment operators, /* Avoid actually calling copy constructors and copy assignment operators,
if possible. */ if possible. */
if (! flag_elide_constructors) if (! flag_elide_constructors && !force_elide)
/* Do things the hard way. */; /* Do things the hard way. */;
else if (cand->num_convs == 1 else if (cand->num_convs == 1
&& (DECL_COPY_CONSTRUCTOR_P (fn) && (DECL_COPY_CONSTRUCTOR_P (fn)
...@@ -8074,7 +8103,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -8074,7 +8103,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
/* It's unsafe to elide the constructor when handling /* It's unsafe to elide the constructor when handling
a noexcept-expression, it may evaluate to the wrong a noexcept-expression, it may evaluate to the wrong
value (c++/53025). */ value (c++/53025). */
&& cp_noexcept_operand == 0) && (force_elide || cp_noexcept_operand == 0))
{ {
tree targ; tree targ;
tree arg = argarray[num_artificial_parms_for (fn)]; tree arg = argarray[num_artificial_parms_for (fn)];
...@@ -8112,6 +8141,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -8112,6 +8141,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
subobject. */ subobject. */
if (CHECKING_P && cxx_dialect >= cxx17) if (CHECKING_P && cxx_dialect >= cxx17)
gcc_assert (TREE_CODE (arg) != TARGET_EXPR gcc_assert (TREE_CODE (arg) != TARGET_EXPR
|| force_elide
/* It's from binding the ref parm to a packed field. */ /* It's from binding the ref parm to a packed field. */
|| convs[0]->need_temporary_p || convs[0]->need_temporary_p
|| seen_error () || seen_error ()
...@@ -8120,7 +8150,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -8120,7 +8150,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
/* [class.copy]: the copy constructor is implicitly defined even if /* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */ the implementation elided its use. */
if (!trivial) if (!trivial && !force_elide)
{ {
if (!mark_used (fn, complain) && !(complain & tf_error)) if (!mark_used (fn, complain) && !(complain & tf_error))
return error_mark_node; return error_mark_node;
...@@ -8207,6 +8237,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) ...@@ -8207,6 +8237,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
} }
} }
gcc_assert (!force_elide);
if (!already_used if (!already_used
&& !mark_used (fn, complain)) && !mark_used (fn, complain))
return error_mark_node; return error_mark_node;
...@@ -8873,23 +8905,11 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args, ...@@ -8873,23 +8905,11 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
{ {
tree arg = (**args)[0]; tree arg = (**args)[0];
/* FIXME P0135 doesn't say how to handle direct initialization from a
type with a suitable conversion operator. Let's handle it like
copy-initialization, but allowing explict conversions. */
tsubst_flags_t sub_complain = tf_warning;
if (!is_dummy_object (instance))
/* If we're using this to initialize a non-temporary object, don't
require the destructor to be accessible. */
sub_complain |= tf_no_cleanup;
if (BRACE_ENCLOSED_INITIALIZER_P (arg) if (BRACE_ENCLOSED_INITIALIZER_P (arg)
&& !CONSTRUCTOR_IS_DIRECT_INIT (arg)) && !TYPE_HAS_LIST_CTOR (class_type)
/* An init-list arg needs to convert to the parm type (83937), so fall && CONSTRUCTOR_NELTS (arg) == 1)
through to normal processing. */ arg = CONSTRUCTOR_ELT (arg, 0)->value;
arg = error_mark_node;
else if (!reference_related_p (class_type, TREE_TYPE (arg)))
arg = perform_implicit_conversion_flags (class_type, arg,
sub_complain,
flags);
if ((TREE_CODE (arg) == TARGET_EXPR if ((TREE_CODE (arg) == TARGET_EXPR
|| TREE_CODE (arg) == CONSTRUCTOR) || TREE_CODE (arg) == CONSTRUCTOR)
&& (same_type_ignoring_top_level_qualifiers_p && (same_type_ignoring_top_level_qualifiers_p
......
// PR c++/81311
// { dg-do link }
struct function
{
template<class F> function(F) { }
};
struct ref
{
operator function&() const;
} r;
struct val
{
operator function() const;
} v;
int main()
{
function f1(r);
function f2(v);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment