-/* Functions related to invoking methods and overloaded functions.
+/* Functions related to invoking -*- C++ -*- methods and overloaded functions.
Copyright (C) 1987-2016 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) and
modified by Brendan Kehoe (brendan@cygnus.com).
tsubst_flags_t);
static int compare_ics (conversion *, conversion *);
static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
-static tree build_java_interface_fn_ref (tree, tree);
#define convert_like(CONV, EXPR, COMPLAIN) \
convert_like_real ((CONV), (EXPR), NULL_TREE, 0, 0, \
/*issue_conversion_warnings=*/true, \
{
/* Core issue 903 says only literal 0 is a null pointer constant. */
if (TREE_CODE (type) == INTEGER_TYPE
+ && !char_type_p (type)
&& TREE_CODE (t) == INTEGER_CST
&& integer_zerop (t)
&& !TREE_OVERFLOW (t))
if (i < CONSTRUCTOR_NELTS (ctor))
val = CONSTRUCTOR_ELT (ctor, i)->value;
+ else if (DECL_INITIAL (field))
+ val = get_nsdmi (field, /*ctor*/false);
else if (TREE_CODE (ftype) == REFERENCE_TYPE)
/* Value-initialization of reference is ill-formed. */
return NULL;
fcode = TREE_CODE (from);
conv = build_conv (ck_lvalue, from, conv);
}
- else if (fromref || (expr && lvalue_p (expr)))
+ /* Wrapping a ck_rvalue around a class prvalue (as a result of using
+ obvalue_p) seems odd, since it's already a prvalue, but that's how we
+ express the copy constructor call required by copy-initialization. */
+ else if (fromref || (expr && obvalue_p (expr)))
{
if (expr)
{
gl_kind = clk_rvalueref;
}
else if (expr)
- {
- gl_kind = lvalue_kind (expr);
- if (gl_kind & clk_class)
- /* A class prvalue is not a glvalue. */
- gl_kind = clk_none;
- }
+ gl_kind = lvalue_kind (expr);
+ else if (CLASS_TYPE_P (from)
+ || TREE_CODE (from) == ARRAY_TYPE)
+ gl_kind = clk_class;
else
gl_kind = clk_none;
- is_lvalue = gl_kind && !(gl_kind & clk_rvalueref);
+
+ /* Don't allow a class prvalue when LOOKUP_NO_TEMP_BIND. */
+ if ((flags & LOOKUP_NO_TEMP_BIND)
+ && (gl_kind & clk_class))
+ gl_kind = clk_none;
+
+ /* Same mask as real_lvalue_p. */
+ is_lvalue = gl_kind && !(gl_kind & (clk_rvalueref|clk_class));
tfrom = from;
if ((gl_kind & clk_bitfield) != 0)
[8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
const and rvalue references to rvalues of compatible class type.
We should also do direct bindings for non-class xvalues. */
- if (related_p
- && (gl_kind
- || (!(flags & LOOKUP_NO_TEMP_BIND)
- && (CLASS_TYPE_P (from)
- || TREE_CODE (from) == ARRAY_TYPE))))
+ if (related_p && gl_kind)
{
/* [dcl.init.ref]
cand = build_user_type_conversion_1 (to, expr, flags, complain);
if (cand)
- conv = cand->second_conv;
+ {
+ if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+ && CONSTRUCTOR_NELTS (expr) == 1
+ && !is_list_ctor (cand->fn))
+ {
+ /* "If C is not an initializer-list constructor and the
+ initializer list has a single element of type cv U, where U is
+ X or a class derived from X, the implicit conversion sequence
+ has Exact Match rank if U is X, or Conversion rank if U is
+ derived from X." */
+ tree elt = CONSTRUCTOR_ELT (expr, 0)->value;
+ tree elttype = TREE_TYPE (elt);
+ if (reference_related_p (to, elttype))
+ return implicit_conversion (to, elttype, elt,
+ c_cast_p, flags, complain);
+ }
+ conv = cand->second_conv;
+ }
/* We used to try to bind a reference to a temporary here, but that
is now handled after the recursive call to this function at the end
/* Return the number of remaining arguments in the parameter list
beginning with ARG. */
-static int
+int
remaining_arguments (tree arg)
{
int n;
case PREDECREMENT_EXPR:
if (TREE_CODE (type1) == BOOLEAN_TYPE)
return;
+ /* FALLTHRU */
case POSTINCREMENT_EXPR:
case PREINCREMENT_EXPR:
if (ARITHMETIC_TYPE_P (type1) || TYPE_PTROB_P (type1))
case UNARY_PLUS_EXPR: /* unary + */
if (TYPE_PTR_P (type1))
break;
+ /* FALLTHRU */
case NEGATE_EXPR:
if (ARITHMETIC_TYPE_P (type1))
break;
type2 = ptrdiff_type_node;
break;
}
+ /* FALLTHRU */
case MULT_EXPR:
case TRUNC_DIV_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
case PLUS_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
break;
+ /* FALLTHRU */
case ARRAY_REF:
if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1) && TYPE_PTROB_P (type2))
{
type2 = ptrdiff_type_node;
break;
}
+ /* FALLTHRU */
case MULT_EXPR:
case TRUNC_DIV_EXPR:
if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
if (code == COND_EXPR)
{
- if (real_lvalue_p (args[i]))
+ if (lvalue_p (args[i]))
vec_safe_push (types[i], build_reference_type (argtypes[i]));
vec_safe_push (types[i], TYPE_MAIN_VARIANT (argtypes[i]));
}
else
{
- if (code == COND_EXPR && real_lvalue_p (args[i]))
+ if (code == COND_EXPR && lvalue_p (args[i]))
vec_safe_push (types[i], build_reference_type (argtypes[i]));
type = non_reference (argtypes[i]);
if (i != 0 || ! ref1)
tree return_type, tree access_path,
tree conversion_path, tsubst_flags_t complain)
{
+ /* Making this work broke PR 71117, so until the committee resolves core
+ issue 2189, let's disable this candidate if there are any viable call
+ operators. */
+ if (any_strictly_viable (*candidates))
+ return NULL;
+
return
add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
NULL_TREE, arglist, return_type, access_path,
static void
add_list_candidates (tree fns, tree first_arg,
- tree init_list, tree totype,
+ const vec<tree, va_gc> *args, tree totype,
tree explicit_targs, bool template_only,
tree conversion_path, tree access_path,
int flags,
struct z_candidate **candidates,
tsubst_flags_t complain)
{
- vec<tree, va_gc> *args;
-
gcc_assert (*candidates == NULL);
/* We're looking for a ctor for list-initialization. */
avoid the copy constructor call for copy-list-initialization. */
flags |= LOOKUP_NO_NARROWING;
+ unsigned nart = num_artificial_parms_for (get_first_fn (fns)) - 1;
+ tree init_list = (*args)[nart];
+
/* Always use the default constructor if the list is empty (DR 990). */
if (CONSTRUCTOR_NELTS (init_list) == 0
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
else if (TYPE_HAS_LIST_CTOR (totype))
{
flags |= LOOKUP_LIST_ONLY;
- args = make_tree_vector_single (init_list);
add_candidates (fns, first_arg, args, NULL_TREE,
explicit_targs, template_only, conversion_path,
access_path, flags, candidates, complain);
return;
}
- args = ctor_to_vec (init_list);
+ /* Expand the CONSTRUCTOR into a new argument vec. */
+ vec<tree, va_gc> *new_args;
+ vec_alloc (new_args, nart + CONSTRUCTOR_NELTS (init_list));
+ for (unsigned i = 0; i < nart; ++i)
+ new_args->quick_push ((*args)[i]);
+ for (unsigned i = 0; i < CONSTRUCTOR_NELTS (init_list); ++i)
+ new_args->quick_push (CONSTRUCTOR_ELT (init_list, i)->value);
/* We aren't looking for list-ctors anymore. */
flags &= ~LOOKUP_LIST_ONLY;
/* We allow more user-defined conversions within an init-list. */
flags &= ~LOOKUP_NO_CONVERSION;
- add_candidates (fns, first_arg, args, NULL_TREE,
+ add_candidates (fns, first_arg, new_args, NULL_TREE,
explicit_targs, template_only, conversion_path,
access_path, flags, candidates, complain);
}
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);
gcc_assert (!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors))
&& !DECL_HAS_VTT_PARM_P (OVL_CURRENT (ctors)));
+ args = make_tree_vector_single (expr);
if (BRACE_ENCLOSED_INITIALIZER_P (expr))
{
/* List-initialization. */
- add_list_candidates (ctors, first_arg, expr, totype, NULL_TREE,
+ add_list_candidates (ctors, first_arg, args, totype, NULL_TREE,
false, TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates, complain);
}
else
{
- args = make_tree_vector_single (expr);
add_candidates (ctors, first_arg, args, NULL_TREE, NULL_TREE, false,
TYPE_BINFO (totype), TYPE_BINFO (totype),
ctorflags, &candidates, complain);
}
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))
{
if (complain & tf_error)
error_at (loc, "conversion from %qT to %qT not considered for "
"non-type template argument", t, type);
- /* and fall through. */
+ /* fall through. */
default:
conv = NULL;
tree
build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
- tree *size, tree *cookie_size, tree size_check,
+ tree *size, tree *cookie_size,
+ tree align_arg, tree size_check,
tree *fn, tsubst_flags_t complain)
{
tree original_size = *size;
tree fns;
struct z_candidate *candidates;
- struct z_candidate *cand;
+ struct z_candidate *cand = NULL;
bool any_viable_p;
if (fn)
we disregard block-scope declarations of "operator new". */
fns = lookup_function_nonclass (fnname, *args, /*block_p=*/false);
+ if (align_arg)
+ {
+ vec<tree, va_gc>* align_args
+ = vec_copy_and_insert (*args, align_arg, 1);
+ cand = perform_overload_resolution (fns, align_args, &candidates,
+ &any_viable_p, tf_none);
+ /* If no aligned allocation function matches, try again without the
+ alignment. */
+ }
+
/* Figure out what function is being called. */
- cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
- complain);
+ if (!cand)
+ cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
+ complain);
/* If no suitable function could be found, issue an error message
and give up. */
result = build_over_call (cand, LOOKUP_NORMAL, complain);
else
{
- obj = convert_like_with_context (cand->convs[0], obj, cand->fn, -1,
- complain);
+ if (DECL_P (cand->fn))
+ obj = convert_like_with_context (cand->convs[0], obj, cand->fn,
+ -1, complain);
+ else
+ obj = convert_like (cand->convs[0], obj, complain);
obj = convert_from_reference (obj);
result = cp_build_function_call_vec (obj, args, complain);
}
If E2 is an xvalue: E1 can be converted to match E2 if E1 can be
implicitly converted to the type "rvalue reference to T2", subject to
the constraint that the reference must bind directly. */
- if (lvalue_or_rvalue_with_address_p (e2))
+ if (glvalue_p (e2))
{
- tree rtype = cp_build_reference_type (t2, !real_lvalue_p (e2));
+ tree rtype = cp_build_reference_type (t2, !lvalue_p (e2));
conv = implicit_conversion (rtype,
t1,
e1,
tree arg3_type;
tree result = NULL_TREE;
tree result_type = NULL_TREE;
- bool lvalue_p = true;
+ bool is_lvalue = true;
struct z_candidate *candidates = 0;
struct z_candidate *cand;
void *p;
if (!arg2)
{
if (complain & tf_error)
- pedwarn (loc, OPT_Wpedantic,
+ pedwarn (loc, OPT_Wpedantic,
"ISO C++ forbids omitting the middle term of a ?: expression");
+ if ((complain & tf_warning) && !truth_value_p (TREE_CODE (arg1)))
+ warn_for_omitted_condop (loc, arg1);
+
/* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */
- if (real_lvalue_p (arg1))
- arg2 = arg1 = stabilize_reference (arg1);
+ if (lvalue_p (arg1))
+ arg2 = arg1 = cp_stabilize_reference (arg1);
else
arg2 = arg1 = save_expr (arg1);
}
if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1)))
{
+ tree arg1_type = TREE_TYPE (arg1);
+
/* If arg1 is another cond_expr choosing between -1 and 0,
then we can use its comparison. It may help to avoid
additional comparison, produce more accurate diagnostics
|| error_operand_p (arg3))
return error_mark_node;
- tree arg1_type = TREE_TYPE (arg1);
arg2_type = TREE_TYPE (arg2);
arg3_type = TREE_TYPE (arg3);
return error_mark_node;
}
- lvalue_p = false;
+ is_lvalue = false;
goto valid_operands;
}
/* [expr.cond]
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)
|| (same_type_ignoring_top_level_qualifiers_p (arg2_type,
arg3_type)
- && lvalue_or_rvalue_with_address_p (arg2)
- && lvalue_or_rvalue_with_address_p (arg3)
- && real_lvalue_p (arg2) == real_lvalue_p (arg3))))
+ && glvalue_p (arg2) && glvalue_p (arg3)
+ && lvalue_p (arg2) == lvalue_p (arg3))))
{
conversion *conv2;
conversion *conv3;
If the second and third operands are glvalues of the same value
category and have the same type, the result is of that type and
value category. */
- if (((real_lvalue_p (arg2) && real_lvalue_p (arg3))
+ if (((lvalue_p (arg2) && lvalue_p (arg3))
|| (xvalue_p (arg2) && xvalue_p (arg3)))
&& same_type_p (arg2_type, arg3_type))
{
cv-qualified) class type, overload resolution is used to
determine the conversions (if any) to be applied to the operands
(_over.match.oper_, _over.built_). */
- lvalue_p = false;
+ is_lvalue = false;
if (!same_type_p (arg2_type, arg3_type)
&& (CLASS_TYPE_P (arg2_type) || CLASS_TYPE_P (arg3_type)))
{
/* We can't use result_type below, as fold might have returned a
throw_expr. */
- if (!lvalue_p)
+ if (!is_lvalue)
{
/* Expand both sides into the same slot, hopefully the target of
the ?: expression. We used to check for TARGET_EXPRs here,
}
}
+/* Returns 1 if P0145R2 says that the LHS of operator CODE is evaluated first,
+ -1 if the RHS is evaluated first, or 0 if the order is unspecified. */
+
+static int
+op_is_ordered (tree_code code)
+{
+ switch (code)
+ {
+ // 5. b @= a
+ case MODIFY_EXPR:
+ return (flag_strong_eval_order > 1 ? -1 : 0);
+
+ // 6. a[b]
+ case ARRAY_REF:
+ return (flag_strong_eval_order > 1 ? 1 : 0);
+
+ // 1. a.b
+ // Not overloadable (yet).
+ // 2. a->b
+ // Only one argument.
+ // 3. a->*b
+ case MEMBER_REF:
+ // 7. a << b
+ case LSHIFT_EXPR:
+ // 8. a >> b
+ case RSHIFT_EXPR:
+ return (flag_strong_eval_order ? 1 : 0);
+
+ default:
+ return 0;
+ }
+}
+
static tree
build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
tree arg2, tree arg3, tree *overload, tsubst_flags_t complain)
case MODIFY_EXPR:
if (code2 != NOP_EXPR)
break;
+ /* FALLTHRU */
case COMPONENT_REF:
case ARRAY_REF:
memonly = true;
else
result = build_over_call (cand, LOOKUP_NORMAL, complain);
- if (processing_template_decl
- && result != NULL_TREE
- && result != error_mark_node
- && DECL_HIDDEN_FRIEND_P (cand->fn))
+ if (trivial_fn_p (cand->fn))
+ /* There won't be a CALL_EXPR. */;
+ else if (result && result != error_mark_node)
{
- tree call = result;
- if (REFERENCE_REF_P (call))
- call = TREE_OPERAND (call, 0);
- /* This prevents build_new_function_call from discarding this
- function during instantiation of the enclosing template. */
- KOENIG_LOOKUP_P (call) = 1;
+ tree call = extract_call_expr (result);
+ CALL_EXPR_OPERATOR_SYNTAX (call) = true;
+
+ if (processing_template_decl && DECL_HIDDEN_FRIEND_P (cand->fn))
+ /* This prevents build_new_function_call from discarding this
+ function during instantiation of the enclosing template. */
+ KOENIG_LOOKUP_P (call) = 1;
+
+ /* Specify evaluation order as per P0145R2. */
+ CALL_EXPR_ORDERED_ARGS (call) = false;
+ switch (op_is_ordered (code))
+ {
+ case -1:
+ CALL_EXPR_REVERSE_ARGS (call) = true;
+ break;
+
+ case 1:
+ CALL_EXPR_ORDERED_ARGS (call) = true;
+ break;
+
+ default:
+ break;
+ }
}
}
else
switch (code)
{
case MODIFY_EXPR:
- return cp_build_modify_expr (arg1, code2, arg2, complain);
+ return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
case INDIRECT_REF:
return cp_build_indirect_ref (arg1, RO_UNARY_STAR, complain);
return ret;
}
+/* CALL was returned by some call-building function; extract the actual
+ CALL_EXPR from any bits that have been tacked on, e.g. by
+ convert_from_reference. */
+
+tree
+extract_call_expr (tree call)
+{
+ while (TREE_CODE (call) == COMPOUND_EXPR)
+ call = TREE_OPERAND (call, 1);
+ if (REFERENCE_REF_P (call))
+ call = TREE_OPERAND (call, 0);
+ if (TREE_CODE (call) == TARGET_EXPR)
+ call = TARGET_EXPR_INITIAL (call);
+ gcc_assert (TREE_CODE (call) == CALL_EXPR
+ || TREE_CODE (call) == AGGR_INIT_EXPR
+ || call == error_mark_node);
+ return call;
+}
+
/* Returns true if FN has two parameters, of which the second has type
size_t. */
second_parm_is_size_t (tree fn)
{
tree t = FUNCTION_ARG_CHAIN (fn);
- return (t
- && same_type_p (TREE_VALUE (t), size_type_node)
- && TREE_CHAIN (t) == void_list_node);
+ if (!t || !same_type_p (TREE_VALUE (t), size_type_node))
+ return false;
+ t = TREE_CHAIN (t);
+ if (t == void_list_node)
+ return true;
+ if (aligned_new_threshold && t
+ && same_type_p (TREE_VALUE (t), align_type_node)
+ && TREE_CHAIN (t) == void_list_node)
+ return true;
+ return false;
+}
+
+/* True if T, an allocation function, has std::align_val_t as its second
+ argument. */
+
+bool
+aligned_allocation_fn_p (tree t)
+{
+ if (!aligned_new_threshold)
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ return (a && same_type_p (TREE_VALUE (a), align_type_node));
+}
+
+/* Returns true iff T, an element of an OVERLOAD chain, is a usual deallocation
+ function (3.7.4.2 [basic.stc.dynamic.deallocation]) with a parameter of
+ std::align_val_t. */
+
+static bool
+aligned_deallocation_fn_p (tree t)
+{
+ if (!aligned_new_threshold)
+ return false;
+
+ /* A template instance is never a usual deallocation function,
+ regardless of its signature. */
+ if (TREE_CODE (t) == TEMPLATE_DECL
+ || primary_template_instantiation_p (t))
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ if (same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ if (!same_type_p (TREE_VALUE (a), size_type_node))
+ return false;
+ a = TREE_CHAIN (a);
+ if (a && same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ return false;
}
/* Returns true iff T, an element of an OVERLOAD chain, is a usual
deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]). */
bool
-non_placement_deallocation_fn_p (tree t)
+usual_deallocation_fn_p (tree t)
{
/* A template instance is never a usual deallocation function,
regardless of its signature. */
of which has type std::size_t (18.2), then this function is a usual
deallocation function. */
bool global = DECL_NAMESPACE_SCOPE_P (t);
- if (FUNCTION_ARG_CHAIN (t) == void_list_node
+ tree chain = FUNCTION_ARG_CHAIN (t);
+ if (!chain)
+ return false;
+ if (chain == void_list_node
|| ((!global || flag_sized_deallocation)
&& second_parm_is_size_t (t)))
return true;
+ if (aligned_deallocation_fn_p (t))
+ return true;
return false;
}
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt)
+ if (usual_deallocation_fn_p (elt)
&& FUNCTION_ARG_CHAIN (elt) == void_list_node)
goto ok;
}
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt))
+ if (usual_deallocation_fn_p (elt))
{
- fn = elt;
- /* "If a class T has a member deallocation function named
- operator delete with exactly one parameter, then that
- function is a usual (non-placement) deallocation
- function. If class T does not declare such an operator
- delete but does declare a member deallocation function named
- operator delete with exactly two parameters, the second of
- which has type std::size_t (18.2), then this function is a
- usual deallocation function."
-
- So in a class (void*) beats (void*, size_t). */
- if (DECL_CLASS_SCOPE_P (fn))
+ if (!fn)
{
- if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
- break;
+ fn = elt;
+ continue;
+ }
+
+ /* -- If the type has new-extended alignment, a function with a
+ parameter of type std::align_val_t is preferred; otherwise a
+ function without such a parameter is preferred. If exactly one
+ preferred function is found, that function is selected and the
+ selection process terminates. If more than one preferred
+ function is found, all non-preferred functions are eliminated
+ from further consideration. */
+ if (aligned_new_threshold)
+ {
+ bool want_align = type_has_new_extended_alignment (type);
+ bool fn_align = aligned_deallocation_fn_p (fn);
+ bool elt_align = aligned_deallocation_fn_p (elt);
+
+ if (elt_align != fn_align)
+ {
+ if (want_align == elt_align)
+ fn = elt;
+ continue;
+ }
}
- /* At global scope (in C++14 and above) the rules are different:
-
- If deallocation function lookup finds both a usual
- deallocation function with only a pointer parameter and a
- usual deallocation function with both a pointer parameter
- and a size parameter, the function to be called is selected
- as follows:
-
- * If the type is complete and if, for the second alternative
- (delete array) only, the operand is a pointer to a class
- type with a non-trivial destructor or a (possibly
- multi-dimensional) array thereof, the function with two
- parameters is selected.
-
- * Otherwise, it is unspecified which of the two deallocation
- functions is selected. */
+
+ /* -- If the deallocation functions have class scope, the one
+ without a parameter of type std::size_t is selected. */
+ bool want_size;
+ if (DECL_CLASS_SCOPE_P (fn))
+ want_size = false;
+
+ /* -- If the type is complete and if, for the second alternative
+ (delete array) only, the operand is a pointer to a class type
+ with a non-trivial destructor or a (possibly multi-dimensional)
+ array thereof, the function with a parameter of type std::size_t
+ is selected.
+
+ -- Otherwise, it is unspecified whether a deallocation function
+ with a parameter of type std::size_t is selected. */
else
{
- bool want_size = COMPLETE_TYPE_P (type);
+ want_size = COMPLETE_TYPE_P (type);
if (code == VEC_DELETE_EXPR
&& !TYPE_VEC_NEW_USES_COOKIE (type))
/* We need a cookie to determine the array size. */
want_size = false;
- bool have_size = (FUNCTION_ARG_CHAIN (fn) != void_list_node);
- if (want_size == have_size)
- break;
}
+ bool fn_size = second_parm_is_size_t (fn);
+ bool elt_size = second_parm_is_size_t (elt);
+ gcc_assert (fn_size != elt_size);
+ if (want_size == elt_size)
+ fn = elt;
}
}
tree ret;
vec<tree, va_gc> *args = make_tree_vector ();
args->quick_push (addr);
- if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
+ if (second_parm_is_size_t (fn))
args->quick_push (size);
+ if (aligned_deallocation_fn_p (fn))
+ {
+ tree al = build_int_cst (align_type_node, TYPE_ALIGN_UNIT (type));
+ args->quick_push (al);
+ }
ret = cp_build_function_call_vec (fn, &args, complain);
release_tree_vector (args);
return ret;
int savew, savee;
vec<tree, va_gc> *args;
+ *diagnostic_kind = DK_UNSPECIFIED;
+
+ /* 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
+ do that now. */
+ if ((lvalue_kind (expr) & clk_packed)
+ && CLASS_TYPE_P (TREE_TYPE (expr))
+ && !type_has_nontrivial_copy_init (TREE_TYPE (expr)))
+ return get_target_expr_sfinae (expr, complain);
+
savew = warningcount + werrorcount, savee = errorcount;
args = make_tree_vector_single (expr);
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
*diagnostic_kind = DK_WARNING;
else if (errorcount > savee)
*diagnostic_kind = DK_ERROR;
- else
- *diagnostic_kind = DK_UNSPECIFIED;
return expr;
}
{
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. */
if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
+ && BRACE_ENCLOSED_INITIALIZER_P (expr)
/* Unless this is for direct-list-initialization. */
- && !DIRECT_LIST_INIT_P (expr)
+ && !CONSTRUCTOR_IS_DIRECT_INIT (expr)
/* And in C++98 a default constructor can't be explicit. */
&& cxx_dialect >= cxx11)
{
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. */
expr = decay_conversion (expr, complain);
if (expr == error_mark_node)
{
- if (complain)
+ if (complain & tf_error)
{
maybe_print_user_conv_context (convs);
if (fn)
if (! MAYBE_CLASS_TYPE_P (totype))
return expr;
- /* Else fall through. */
+ /* Fall through. */
case ck_base:
if (convs->kind == ck_base && !convs->need_temporary_p)
{
{
tree extype = TREE_TYPE (expr);
if (TYPE_REF_IS_RVALUE (ref_type)
- && real_lvalue_p (expr))
- error_at (loc, "cannot bind %qT lvalue to %qT",
- extype, totype);
- else if (!TYPE_REF_IS_RVALUE (ref_type) && !real_lvalue_p (expr)
+ && lvalue_p (expr))
+ error_at (loc, "cannot bind rvalue reference of type %qT to "
+ "lvalue of type %qT", totype, extype);
+ else if (!TYPE_REF_IS_RVALUE (ref_type) && !lvalue_p (expr)
&& !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
- error_at (loc, "invalid initialization of non-const reference of "
- "type %qT from an rvalue of type %qT", totype, extype);
+ error_at (loc, "cannot bind non-const lvalue reference of "
+ "type %qT to an rvalue of type %qT", totype, extype);
else if (!reference_compatible_p (TREE_TYPE (totype), extype))
- error_at (loc, "binding %qT to reference of type %qT "
- "discards qualifiers", extype, totype);
+ error_at (loc, "binding reference of type %qT to %qT "
+ "discards qualifiers", totype, extype);
else
gcc_unreachable ();
maybe_print_user_conv_context (convs);
for a non-reference copy-initialization (8.5). */
tree type = TREE_TYPE (ref_type);
- cp_lvalue_kind lvalue = real_lvalue_p (expr);
+ cp_lvalue_kind lvalue = lvalue_kind (expr);
gcc_assert (same_type_ignoring_top_level_qualifiers_p
(type, next_conversion (convs)->type));
return convert_from_reference (expr);
}
- return build_va_arg (loc, expr, type);
+ tree ret = build_va_arg (loc, expr, type);
+ if (CLASS_TYPE_P (type))
+ /* Wrap the VA_ARG_EXPR in a TARGET_EXPR now so other code doesn't need to
+ know how to handle it. */
+ ret = get_target_expr (ret);
+ return ret;
}
/* TYPE has been given to va_arg. Apply the default conversions which
return val;
}
-/* Returns true iff FN is a function with magic varargs, i.e. ones for
- which no conversions at all should be done. This is true for some
- builtins which don't act like normal functions. */
+/* Returns non-zero iff FN is a function with magic varargs, i.e. ones for
+ which just decay_conversion or no conversions at all should be done.
+ This is true for some builtins which don't act like normal functions.
+ Return 2 if no conversions at all should be done, 1 if just
+ decay_conversion. Return 3 for special treatment of the 3rd argument
+ for __builtin_*_overflow_p. */
-bool
+int
magic_varargs_p (tree fn)
{
if (flag_cilkplus && is_cilkplus_reduce_builtin (fn) != BUILT_IN_NONE)
- return true;
+ return 2;
- if (DECL_BUILT_IN (fn))
+ if (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fn))
{
case BUILT_IN_CLASSIFY_TYPE:
case BUILT_IN_CONSTANT_P:
case BUILT_IN_NEXT_ARG:
case BUILT_IN_VA_START:
- return true;
+ return 1;
+
+ case BUILT_IN_ADD_OVERFLOW_P:
+ case BUILT_IN_SUB_OVERFLOW_P:
+ case BUILT_IN_MUL_OVERFLOW_P:
+ return 3;
default:;
return lookup_attribute ("type generic",
TYPE_ATTRIBUTES (TREE_TYPE (fn))) != 0;
}
- return false;
+ return 0;
}
/* Returns the decl of the dispatcher function if FN is a function version. */
static bool
unsafe_copy_elision_p (tree target, tree exp)
{
+ /* Copy elision only happens with a TARGET_EXPR. */
+ if (TREE_CODE (exp) != TARGET_EXPR)
+ return false;
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
- if (type == CLASSTYPE_AS_BASE (type))
+ /* It's safe to elide the copy for a class with no tail padding. */
+ if (tree_int_cst_equal (TYPE_SIZE (type), CLASSTYPE_SIZE (type)))
return false;
- if (!is_base_field_ref (target)
- && resolves_to_fixed_type_p (target, NULL))
+ /* It's safe to elide the copy if we aren't initializing a base object. */
+ if (!is_base_field_ref (target))
return false;
tree init = TARGET_EXPR_INITIAL (exp);
/* build_compound_expr pushes COMPOUND_EXPR inside TARGET_EXPR. */
" (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
}
/* Ellipsis */
+ int magic = magic_varargs_p (fn);
for (; arg_index < vec_safe_length (args); ++arg_index)
{
tree a = (*args)[arg_index];
- if (magic_varargs_p (fn))
- /* Do no conversions for magic varargs. */
- a = mark_type_use (a);
+ if ((magic == 3 && arg_index == 2) || magic == 2)
+ {
+ /* Do no conversions for certain magic varargs. */
+ a = mark_type_use (a);
+ if (TREE_CODE (a) == FUNCTION_DECL && reject_gcc_builtin (a))
+ return error_mark_node;
+ }
+ else if (magic != 0)
+ /* For other magic varargs only do decay_conversion. */
+ a = decay_conversion (a, complain);
else if (DECL_CONSTRUCTOR_P (fn)
&& same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (fn),
TREE_TYPE (a)))
}
else
a = convert_arg_to_ellipsis (a, complain);
+ if (a == error_mark_node)
+ return error_mark_node;
argarray[j++] = a;
}
else
arg = cp_build_indirect_ref (arg, RO_NULL, complain);
+ /* In C++17 we shouldn't be copying a TARGET_EXPR except into a base
+ subobject. */
+ if (CHECKING_P && cxx_dialect >= cxx1z)
+ gcc_assert (TREE_CODE (arg) != TARGET_EXPR
+ || seen_error ()
+ /* See unsafe_copy_elision_p. */
+ || DECL_BASE_CONSTRUCTOR_P (fn));
+
/* [class.copy]: the copy constructor is implicitly defined even if
the implementation elided its use. */
if (!trivial || DECL_DELETED_FN (fn))
else if (trivial)
return force_target_expr (DECL_CONTEXT (fn), arg, complain);
}
- else if (trivial
- || (TREE_CODE (arg) == TARGET_EXPR
- && !unsafe_copy_elision_p (fa, arg)))
+ else if ((trivial || TREE_CODE (arg) == TARGET_EXPR)
+ && !unsafe_copy_elision_p (fa, arg))
{
- tree to = stabilize_reference (cp_build_indirect_ref (fa, RO_NULL,
- complain));
+ tree to = cp_stabilize_reference (cp_build_indirect_ref (fa,
+ RO_NULL,
+ complain));
val = build2 (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
return val;
&& trivial_fn_p (fn)
&& !DECL_DELETED_FN (fn))
{
- tree to = stabilize_reference
+ tree to = cp_stabilize_reference
(cp_build_indirect_ref (argarray[0], RO_NULL, complain));
tree type = TREE_TYPE (to);
tree as_base = CLASSTYPE_AS_BASE (type);
if (is_really_empty_class (type))
{
/* Avoid copying empty classes. */
- val = build2 (COMPOUND_EXPR, void_type_node, to, arg);
- TREE_NO_WARNING (val) = 1;
- val = build2 (COMPOUND_EXPR, type, val, to);
+ val = build2 (COMPOUND_EXPR, type, arg, to);
TREE_NO_WARNING (val) = 1;
}
else if (tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (as_base)))
return val;
}
- else if (DECL_DESTRUCTOR_P (fn)
- && trivial_fn_p (fn)
- && !DECL_DELETED_FN (fn))
- return fold_convert (void_type_node, argarray[0]);
- /* FIXME handle trivial default constructor, too. */
+ else if (!DECL_DELETED_FN (fn)
+ && trivial_fn_p (fn))
+ {
+ if (DECL_DESTRUCTOR_P (fn))
+ return fold_convert (void_type_node, argarray[0]);
+ else if (default_ctor_p (fn))
+ {
+ if (is_dummy_object (argarray[0]))
+ return force_target_expr (DECL_CONTEXT (fn), void_node, complain);
+ else
+ return cp_build_indirect_ref (argarray[0], RO_NULL, complain);
+ }
+ }
/* For calls to a multi-versioned function, overload resolution
returns the function with the highest target priority, that is,
if (TREE_SIDE_EFFECTS (argarray[0]))
argarray[0] = save_expr (argarray[0]);
t = build_pointer_type (TREE_TYPE (fn));
- if (DECL_CONTEXT (fn) && TYPE_JAVA_INTERFACE (DECL_CONTEXT (fn)))
- fn = build_java_interface_fn_ref (fn, argarray[0]);
- else
- fn = build_vfn_ref (argarray[0], DECL_VINDEX (fn));
+ fn = build_vfn_ref (argarray[0], DECL_VINDEX (fn));
TREE_TYPE (fn) = t;
}
else
}
tree call = build_cxx_call (fn, nargs, argarray, complain|decltype_flag);
- if (TREE_CODE (call) == CALL_EXPR
- && (cand->flags & LOOKUP_LIST_INIT_CTOR))
- CALL_EXPR_LIST_INIT_P (call) = true;
+ if (call != error_mark_node
+ && cand->flags & LOOKUP_LIST_INIT_CTOR)
+ {
+ tree c = extract_call_expr (call);
+ /* build_new_op_1 will clear this when appropriate. */
+ CALL_EXPR_ORDERED_ARGS (c) = true;
+ }
return call;
}
for (i = 0; i < nargs; i++)
argarray[i] = fold_non_dependent_expr (argarray[i]);
- if (!check_builtin_function_arguments (fndecl, nargs, argarray))
+ if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
+ nargs, argarray))
return error_mark_node;
}
return convert_from_reference (fn);
}
-static GTY(()) tree java_iface_lookup_fn;
-
-/* Make an expression which yields the address of the Java interface
- method FN. This is achieved by generating a call to libjava's
- _Jv_LookupInterfaceMethodIdx(). */
-
-static tree
-build_java_interface_fn_ref (tree fn, tree instance)
-{
- tree lookup_fn, method, idx;
- tree klass_ref, iface, iface_ref;
- int i;
-
- if (!java_iface_lookup_fn)
- {
- tree ftype = build_function_type_list (ptr_type_node,
- ptr_type_node, ptr_type_node,
- java_int_type_node, NULL_TREE);
- java_iface_lookup_fn
- = add_builtin_function ("_Jv_LookupInterfaceMethodIdx", ftype,
- 0, NOT_BUILT_IN, NULL, NULL_TREE);
- }
-
- /* Look up the pointer to the runtime java.lang.Class object for `instance'.
- This is the first entry in the vtable. */
- klass_ref = build_vtbl_ref (cp_build_indirect_ref (instance, RO_NULL,
- tf_warning_or_error),
- integer_zero_node);
-
- /* Get the java.lang.Class pointer for the interface being called. */
- iface = DECL_CONTEXT (fn);
- iface_ref = lookup_field (iface, get_identifier ("class$"), 0, false);
- if (!iface_ref || !VAR_P (iface_ref)
- || DECL_CONTEXT (iface_ref) != iface)
- {
- error ("could not find class$ field in java interface type %qT",
- iface);
- return error_mark_node;
- }
- iface_ref = build_address (iface_ref);
- iface_ref = convert (build_pointer_type (iface), iface_ref);
-
- /* Determine the itable index of FN. */
- i = 1;
- for (method = TYPE_METHODS (iface); method; method = DECL_CHAIN (method))
- {
- if (!DECL_VIRTUAL_P (method))
- continue;
- if (fn == method)
- break;
- i++;
- }
- idx = build_int_cst (NULL_TREE, i);
-
- lookup_fn = build1 (ADDR_EXPR,
- build_pointer_type (TREE_TYPE (java_iface_lookup_fn)),
- java_iface_lookup_fn);
- return build_call_nary (ptr_type_node, lookup_fn,
- 3, klass_ref, iface_ref, idx);
-}
-
/* Returns the value to use for the in-charge parameter when making a
call to a function with the indicated NAME.
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
vtt = decay_conversion (vtt, complain);
if (vtt == error_mark_node)
return error_mark_node;
- vtt = build3 (COND_EXPR, TREE_TYPE (vtt),
- build2 (EQ_EXPR, boolean_type_node,
- current_in_charge_parm, integer_zero_node),
- current_vtt_parm,
- vtt);
+ vtt = build_if_in_charge (vtt, current_vtt_parm);
if (BINFO_SUBVTT_INDEX (binfo))
sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
else
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;
}
/* Get the high-water mark for the CONVERSION_OBSTACK. */
p = conversion_obstack_alloc (0);
+ /* The number of arguments artificial parms in ARGS; we subtract one because
+ there's no 'this' in ARGS. */
+ unsigned skip = num_artificial_parms_for (fn) - 1;
+
/* If CONSTRUCTOR_IS_DIRECT_INIT is set, this was a T{ } form
initializer, not T({ }). */
- if (DECL_CONSTRUCTOR_P (fn) && args != NULL && !vec_safe_is_empty (*args)
- && DIRECT_LIST_INIT_P ((**args)[0]))
+ if (DECL_CONSTRUCTOR_P (fn)
+ && vec_safe_length (user_args) > skip
+ && DIRECT_LIST_INIT_P ((*user_args)[skip]))
{
- tree init_list = (**args)[0];
+ tree init_list = (*user_args)[skip];
tree init = NULL_TREE;
- gcc_assert ((*args)->length () == 1
+ gcc_assert (user_args->length () == skip + 1
&& !(flags & LOOKUP_ONLYCONVERTING));
/* If the initializer list has no elements and T is a class type with
}
/* Otherwise go ahead with overload resolution. */
- add_list_candidates (fns, first_mem_arg, init_list,
+ add_list_candidates (fns, first_mem_arg, user_args,
basetype, explicit_targs, template_only,
conversion_path, access_binfo, flags,
&candidates, complain);
we know we really need it. */
cand->first_arg = instance;
}
+ else if (any_dependent_bases_p ())
+ /* We can't tell until instantiation time whether we can use
+ *this as the implicit object argument. */;
else
{
if (complain & tf_error)
"default argument mismatch in "
"overload resolution"))
{
- inform (input_location,
- " candidate 1: %q+#F", cand1->fn);
- inform (input_location,
- " candidate 2: %q+#F", cand2->fn);
+ inform (DECL_SOURCE_LOCATION (cand1->fn),
+ " candidate 1: %q#F", cand1->fn);
+ inform (DECL_SOURCE_LOCATION (cand2->fn),
+ " candidate 2: %q#F", cand2->fn);
}
}
else
convert_like (conv, expr, complain);
else if (!CP_TYPE_CONST_P (TREE_TYPE (type))
&& !TYPE_REF_IS_RVALUE (type)
- && !real_lvalue_p (expr))
+ && !lvalue_p (expr))
error_at (loc, "invalid initialization of non-const reference of "
"type %qT from an rvalue of type %qT",
type, TREE_TYPE (expr));
return init;
if (TREE_CODE (type) == REFERENCE_TYPE)
init = extend_ref_init_temps_1 (decl, init, cleanups);
- else if (is_std_init_list (type))
+ else
{
- /* The temporary array underlying a std::initializer_list
- is handled like a reference temporary. */
tree ctor = init;
if (TREE_CODE (ctor) == TARGET_EXPR)
ctor = TARGET_EXPR_INITIAL (ctor);
if (TREE_CODE (ctor) == CONSTRUCTOR)
{
- tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
- array = extend_ref_init_temps_1 (decl, array, cleanups);
- CONSTRUCTOR_ELT (ctor, 0)->value = array;
+ if (is_std_init_list (type))
+ {
+ /* The temporary array underlying a std::initializer_list
+ is handled like a reference temporary. */
+ tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
+ array = extend_ref_init_temps_1 (decl, array, cleanups);
+ CONSTRUCTOR_ELT (ctor, 0)->value = array;
+ }
+ else
+ {
+ unsigned i;
+ constructor_elt *p;
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ctor);
+ FOR_EACH_VEC_SAFE_ELT (elts, i, p)
+ p->value = extend_ref_init_temps (decl, p->value, cleanups);
+ }
}
}
- else if (TREE_CODE (init) == CONSTRUCTOR)
- {
- unsigned i;
- constructor_elt *p;
- vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (init);
- FOR_EACH_VEC_SAFE_ELT (elts, i, p)
- p->value = extend_ref_init_temps (decl, p->value, cleanups);
- }
return init;
}