creating a garbage BASELINK; constructors can't be inherited. */
ctors = lookup_fnfields_slot (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 >= cxx1z
+ && BRACE_ENCLOSED_INITIALIZER_P (expr)
+ && CONSTRUCTOR_NELTS (expr) == 1)
+ fromtype = TREE_TYPE (CONSTRUCTOR_ELT (expr, 0)->value);
+
if (MAYBE_CLASS_TYPE_P (fromtype))
{
tree to_nonref = non_reference (totype);
}
if (conv_fns)
- first_arg = expr;
+ {
+ if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ /* FIXME see above about C++17. */
+ first_arg = CONSTRUCTOR_ELT (expr, 0)->value;
+ else
+ first_arg = expr;
+ }
for (; conv_fns; conv_fns = TREE_CHAIN (conv_fns))
{
*diagnostic_kind = DK_UNSPECIFIED;
- if (TREE_CODE (expr) == CONSTRUCTOR)
- expr = get_target_expr_sfinae (expr, complain);
- if (early_elide_copy (type, expr))
- return expr;
-
/* If the source is a packed field, calling the copy constructor will require
binding the field to the reference parameter to the copy constructor, and
we'll end up with an infinite loop. If we can use a bitwise copy, then
{
struct z_candidate *cand = convs->cand;
tree convfn = cand->fn;
- unsigned i;
/* When converting from an init list we consider explicit
constructors, but actually trying to call one is an error. */
expr = mark_rvalue_use (expr);
- /* Set user_conv_p on the argument conversions, so rvalue/base
- handling knows not to allow any more UDCs. */
- for (i = 0; i < cand->num_convs; ++i)
- cand->convs[i]->user_conv_p = true;
-
- expr = build_over_call (cand, LOOKUP_NORMAL, complain);
+ /* Pass LOOKUP_NO_CONVERSION so rvalue/base handling knows not to allow
+ any more UDCs. */
+ expr = build_over_call (cand, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
+ complain);
/* If this is a constructor or a function returning an aggr type,
we need to build up a TARGET_EXPR. */
flags |= LOOKUP_ONLYCONVERTING;
if (convs->rvaluedness_matches_p)
flags |= LOOKUP_PREFER_RVALUE;
+ if (TREE_CODE (expr) == TARGET_EXPR
+ && TARGET_EXPR_LIST_INIT_P (expr))
+ /* Copy-list-initialization doesn't actually involve a copy. */
+ return expr;
expr = build_temp (expr, totype, flags, &diag_kind, complain);
if (diag_kind && complain)
{
" (you can disable this with -fno-deduce-init-list)");
}
}
+
+ /* Set user_conv_p on the argument conversions, so rvalue/base handling
+ knows not to allow any more UDCs. This needs to happen after we
+ process cand->warnings. */
+ if (flags & LOOKUP_NO_CONVERSION)
+ conv->user_conv_p = true;
+
val = convert_like_with_context (conv, arg, fn, i - is_method,
conversion_warning
? complain
subobject. */
if (CHECKING_P && cxx_dialect >= cxx1z)
gcc_assert (TREE_CODE (arg) != TARGET_EXPR
- // FIXME we shouldn't copy for direct-init either
- || !(flags & LOOKUP_ONLYCONVERTING)
+ || seen_error ()
/* See unsafe_copy_elision_p. */
|| DECL_BASE_CONSTRUCTOR_P (fn));
return NULL_TREE;
}
+/* We've built up a constructor call RET. Complain if it delegates to the
+ constructor we're currently compiling. */
+
+static void
+check_self_delegation (tree ret)
+{
+ if (TREE_CODE (ret) == TARGET_EXPR)
+ ret = TARGET_EXPR_INITIAL (ret);
+ tree fn = cp_get_callee_fndecl (ret);
+ if (fn && DECL_ABSTRACT_ORIGIN (fn) == current_function_decl)
+ error ("constructor delegates to itself");
+}
+
/* Build a call to a constructor, destructor, or an assignment
operator for INSTANCE, an expression with class type. NAME
indicates the special member function to call; *ARGS are the
gcc_assert (instance != NULL_TREE);
+ /* In C++17, "If the initializer expression is a prvalue and the
+ cv-unqualified version of the source type is the same class as the class
+ of the destination, the initializer expression is used to initialize the
+ destination object." Handle that here to avoid doing overload
+ resolution. */
+ if (cxx_dialect >= cxx1z
+ && args && vec_safe_length (*args) == 1
+ && name == complete_ctor_identifier)
+ {
+ 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. */
+ if (!reference_related_p (class_type, TREE_TYPE (arg)))
+ arg = perform_implicit_conversion_flags (class_type, arg,
+ tf_warning, flags);
+ if (TREE_CODE (arg) == TARGET_EXPR
+ && (same_type_ignoring_top_level_qualifiers_p
+ (class_type, TREE_TYPE (arg))))
+ {
+ if (is_dummy_object (instance))
+ return arg;
+ if ((complain & tf_error)
+ && (flags & LOOKUP_DELEGATING_CONS))
+ check_self_delegation (arg);
+ /* Avoid change of behavior on Wunused-var-2.C. */
+ mark_lvalue_use (instance);
+ return build2 (INIT_EXPR, class_type, instance, arg);
+ }
+ }
+
fns = lookup_fnfields (binfo, name, 1);
/* When making a call to a constructor or destructor for a subobject
if ((complain & tf_error)
&& (flags & LOOKUP_DELEGATING_CONS)
- && name == complete_ctor_identifier
- && TREE_CODE (ret) == CALL_EXPR
- && (DECL_ABSTRACT_ORIGIN (TREE_OPERAND (CALL_EXPR_FN (ret), 0))
- == current_function_decl))
- error ("constructor delegates to itself");
+ && name == complete_ctor_identifier)
+ check_self_delegation (ret);
return ret;
}
return result;
}
-/* Returns true if we should avoid even doing overload resolution for copying
- EXPR to initialize a TYPE. */
-
-bool
-early_elide_copy (tree type, tree expr)
-{
- if (TREE_CODE (expr) != TARGET_EXPR)
- return false;
- /* List-initialization and direct-initialization don't involve a copy. */
- if (TARGET_EXPR_LIST_INIT_P (expr)
- || TARGET_EXPR_DIRECT_INIT_P (expr))
- return true;
- /* In C++17, "If the initializer expression is a prvalue and the
- cv-unqualified version of the source type is the same class as the class
- of the destination, the initializer expression is used to initialize the
- destination object." */
- return (cxx_dialect >= cxx1z
- && (same_type_ignoring_top_level_qualifiers_p
- (type, TREE_TYPE (expr))));
-}
-
/* Conversion...
FLAGS indicates how we should behave. */
if (error_operand_p (e))
return error_mark_node;
- if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP)
- && !early_elide_copy (type, e))
+ if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP))
/* We need a new temporary; don't take this shortcut. */;
else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
{
init = reshape_init (type, init, complain);
}
- /* Also pull out a TARGET_EXPR that we want to avoid copying. */
- if (init && true_exp == exp
- && TREE_CODE (init) == TREE_LIST
- && list_length (init) == 1
- && early_elide_copy (type, TREE_VALUE (init)))
- init = TREE_VALUE (init);
-
if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
&& CP_AGGREGATE_TYPE_P (type))
/* A brace-enclosed initializer for an aggregate. In C++0x this can
initializer, whether that happened just above or in
cp_parser_late_parsing_nsdmi.
- A TARGET_EXPR for which early_elide_copy is true represents the whole
- initialization, so we shouldn't build up another ctor call. */
-
+ A TARGET_EXPR with TARGET_EXPR_DIRECT_INIT_P or TARGET_EXPR_LIST_INIT_P
+ set represents the whole initialization, so we shouldn't build up
+ another ctor call. */
if (init
&& (TREE_CODE (init) == CONSTRUCTOR
- || early_elide_copy (type, init))
+ || (TREE_CODE (init) == TARGET_EXPR
+ && (TARGET_EXPR_DIRECT_INIT_P (init)
+ || TARGET_EXPR_LIST_INIT_P (init))))
&& same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), type))
{
/* Early initialization via a TARGET_EXPR only works for