/* The next conversion in the chain. Since the conversions are
arranged from outermost to innermost, the NEXT conversion will
actually be performed before this conversion. This variant is
- used only when KIND is neither ck_identity nor ck_ambig. */
+ used only when KIND is neither ck_identity, ck_ambig nor
+ ck_list. Please use the next_conversion function instead
+ of using this field directly. */
conversion *next;
/* The expression at the beginning of the conversion chain. This
variant is used only if KIND is ck_identity or ck_ambig. */
tree expr;
- /* The array of conversions for an initializer_list. */
+ /* The array of conversions for an initializer_list, so this
+ variant is used only when KIN D is ck_list. */
conversion **list;
} u;
/* The function candidate corresponding to this conversion
static conversion *reference_binding (tree, tree, tree, bool, int);
static conversion *build_conv (conversion_kind, tree, conversion *);
static conversion *build_list_conv (tree, tree, int);
+static conversion *next_conversion (conversion *);
static bool is_subseq (conversion *, conversion *);
static conversion *maybe_handle_ref_bind (conversion **);
static void maybe_handle_implicit_object (conversion **);
}
}
+/* Update various flags in cfun and the call itself based on what is being
+ called. Split out of build_call_a so that bot_manip can use it too. */
+
+void
+set_flags_from_callee (tree call)
+{
+ int nothrow;
+ tree decl = get_callee_fndecl (call);
+
+ /* We check both the decl and the type; a function may be known not to
+ throw without being declared throw(). */
+ nothrow = ((decl && TREE_NOTHROW (decl))
+ || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (call)))));
+
+ if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
+ cp_function_chain->can_throw = 1;
+
+ if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain)
+ current_function_returns_abnormally = 1;
+
+ TREE_NOTHROW (call) = nothrow;
+}
+
tree
build_call_a (tree function, int n, tree *argarray)
{
- int is_constructor = 0;
- int nothrow;
tree decl;
tree result_type;
tree fntype;
if (SCALAR_TYPE_P (result_type) || VOID_TYPE_P (result_type))
result_type = cv_unqualified (result_type);
- if (TREE_CODE (function) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
- {
- decl = TREE_OPERAND (function, 0);
- if (!TREE_USED (decl))
- {
- /* We invoke build_call directly for several library
- functions. These may have been declared normally if
- we're building libgcc, so we can't just check
- DECL_ARTIFICIAL. */
- gcc_assert (DECL_ARTIFICIAL (decl)
- || !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
- "__", 2));
- mark_used (decl);
- }
- }
- else
- decl = NULL_TREE;
-
- /* We check both the decl and the type; a function may be known not to
- throw without being declared throw(). */
- nothrow = ((decl && TREE_NOTHROW (decl))
- || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (function))));
+ function = build_call_array_loc (input_location,
+ result_type, function, n, argarray);
+ set_flags_from_callee (function);
- if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
- cp_function_chain->can_throw = 1;
+ decl = get_callee_fndecl (function);
- if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain)
- current_function_returns_abnormally = 1;
+ if (decl && !TREE_USED (decl))
+ {
+ /* We invoke build_call directly for several library
+ functions. These may have been declared normally if
+ we're building libgcc, so we can't just check
+ DECL_ARTIFICIAL. */
+ gcc_assert (DECL_ARTIFICIAL (decl)
+ || !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
+ "__", 2));
+ mark_used (decl);
+ }
if (decl && TREE_DEPRECATED (decl))
warn_deprecated_use (decl, NULL_TREE);
require_complete_eh_spec_types (fntype, decl);
- if (decl && DECL_CONSTRUCTOR_P (decl))
- is_constructor = 1;
+ TREE_HAS_CONSTRUCTOR (function) = (decl && DECL_CONSTRUCTOR_P (decl));
/* Don't pass empty class objects by value. This is useful
for tags in STL, which are used to control overload resolution.
We don't need to handle other cases of copying empty classes. */
if (! decl || ! DECL_BUILT_IN (decl))
for (i = 0; i < n; i++)
- if (is_empty_class (TREE_TYPE (argarray[i]))
- && ! TREE_ADDRESSABLE (TREE_TYPE (argarray[i])))
- {
- tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (argarray[i]));
- argarray[i] = build2 (COMPOUND_EXPR, TREE_TYPE (t),
- argarray[i], t);
- }
-
- function = build_call_array_loc (input_location,
- result_type, function, n, argarray);
- TREE_HAS_CONSTRUCTOR (function) = is_constructor;
- TREE_NOTHROW (function) = nothrow;
+ {
+ tree arg = CALL_EXPR_ARG (function, i);
+ if (is_empty_class (TREE_TYPE (arg))
+ && ! TREE_ADDRESSABLE (TREE_TYPE (arg)))
+ {
+ tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
+ arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
+ CALL_EXPR_ARG (function, i) = arg;
+ }
+ }
return function;
}
rr_none,
rr_arity,
rr_explicit_conversion,
+ rr_template_conversion,
rr_arg_conversion,
rr_bad_arg_conversion,
rr_template_unification,
{
/* Core issue 903 says only literal 0 is a null pointer constant. */
if (cxx_dialect < cxx0x)
- {
- t = integral_constant_value (t);
- STRIP_NOPS (t);
- }
+ t = integral_constant_value (t);
+ STRIP_NOPS (t);
if (integer_zerop (t) && !TREE_OVERFLOW (t))
return true;
}
}
static struct rejection_reason *
+template_conversion_rejection (tree from, tree to)
+{
+ struct rejection_reason *r = alloc_rejection (rr_template_conversion);
+ r->u.conversion.n_arg = 0;
+ r->u.conversion.from_type = from;
+ r->u.conversion.to_type = to;
+ return r;
+}
+
+static struct rejection_reason *
template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
const tree *args, unsigned int nargs,
tree return_type, unification_kind_t strict,
return t;
}
+/* Return the next conversion of the conversion chain (if applicable),
+ or NULL otherwise. Please use this function instead of directly
+ accessing fields of struct conversion. */
+
+static conversion *
+next_conversion (conversion *conv)
+{
+ if (conv == NULL
+ || conv->kind == ck_identity
+ || conv->kind == ck_ambig
+ || conv->kind == ck_list)
+ return NULL;
+ return conv->u.next;
+}
+
/* Subroutine of build_aggr_conv: check whether CTOR, a braced-init-list,
is a valid aggregate initializer for array type ATYPE. */
|| expr == error_mark_node)
return NULL;
+ /* Other flags only apply to the primary function in overload
+ resolution, or after we've chosen one. */
+ flags &= (LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION|LOOKUP_COPY_PARM
+ |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
+ |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
+
if (TREE_CODE (to) == REFERENCE_TYPE)
conv = reference_binding (to, from, expr, c_cast_p, flags);
else
&& (flags & LOOKUP_NO_CONVERSION) == 0)
{
struct z_candidate *cand;
- int convflags = (flags & (LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING
- |LOOKUP_NO_NARROWING));
if (CLASS_TYPE_P (to)
&& BRACE_ENCLOSED_INITIALIZER_P (expr)
&& !CLASSTYPE_NON_AGGREGATE (complete_type (to)))
return build_aggr_conv (to, expr, flags);
- cand = build_user_type_conversion_1 (to, expr, convflags);
+ cand = build_user_type_conversion_1 (to, expr, flags);
if (cand)
conv = cand->second_conv;
|| MAYBE_CLASS_TYPE_P (type1)
|| TREE_CODE (type1) == ENUMERAL_TYPE))
{
+ if (TYPE_PTR_P (type1) || TYPE_PTR_TO_MEMBER_P (type1))
+ {
+ tree cptype = composite_pointer_type (type1, type2,
+ error_mark_node,
+ error_mark_node,
+ CPO_CONVERSION,
+ tf_none);
+ if (cptype != error_mark_node)
+ {
+ build_builtin_candidate
+ (candidates, fnname, cptype, cptype, args, argtypes, flags);
+ return;
+ }
+ }
+
build_builtin_candidate
(candidates, fnname, type1, type1, args, argtypes, flags);
build_builtin_candidate
"conversion", r->u.conversion.from_type,
r->u.conversion.to_type);
break;
+ case rr_template_conversion:
+ inform (loc, " conversion from return type %qT of template "
+ "conversion function specialization to %qT is not an "
+ "exact match", r->u.conversion.from_type,
+ r->u.conversion.to_type);
+ break;
case rr_template_unification:
/* We use template_unification_error_rejection if unification caused
actual non-SFINAE errors, in which case we don't need to repeat
merge_conversion_sequences (conversion *user_seq, conversion *std_seq)
{
conversion **t;
+ bool bad = user_seq->bad_p;
gcc_assert (user_seq->kind == ck_user);
/* Find the end of the second conversion sequence. */
- t = &(std_seq);
- while ((*t)->kind != ck_identity)
- t = &((*t)->u.next);
+ for (t = &std_seq; (*t)->kind != ck_identity; t = &((*t)->u.next))
+ {
+ /* The entire sequence is a user-conversion sequence. */
+ (*t)->user_conv_p = true;
+ if (bad)
+ (*t)->bad_p = true;
+ }
/* Replace the identity conversion with the user conversion
sequence. */
*t = user_seq;
- /* The entire sequence is a user-conversion sequence. */
- std_seq->user_conv_p = true;
-
return std_seq;
}
build_user_type_conversion_1 (tree totype, tree expr, int flags)
{
struct z_candidate *candidates, *cand;
- tree fromtype = TREE_TYPE (expr);
+ tree fromtype;
tree ctors = NULL_TREE;
tree conv_fns = NULL_TREE;
conversion *conv = NULL;
bool any_viable_p;
int convflags;
+ if (!expr)
+ return NULL;
+
+ fromtype = TREE_TYPE (expr);
+
/* We represent conversion within a hierarchy using RVALUE_CONV and
BASE_CONV, as specified by [over.best.ics]; these become plain
constructor calls, as specified in [dcl.init]. */
= bad_arg_conversion_rejection (NULL_TREE, -1,
rettype, totype);
}
+ else if (primary_template_instantiation_p (cand->fn)
+ && ics->rank > cr_exact)
+ {
+ /* 13.3.3.1.2: If the user-defined conversion is specified by
+ a specialization of a conversion function template, the
+ second standard conversion sequence shall have exact match
+ rank. */
+ cand->viable = -1;
+ cand->reason = template_conversion_rejection (rettype, totype);
+ }
}
}
? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
build_identity_conv (TREE_TYPE (expr), expr));
conv->cand = cand;
+ if (cand->viable == -1)
+ conv->bad_p = true;
/* Remember that this was a list-initialization. */
if (flags & LOOKUP_NO_NARROWING)
cand->second_conv = merge_conversion_sequences (conv,
cand->second_conv);
- if (cand->viable == -1)
- cand->second_conv->bad_p = true;
-
return cand;
}
return error_mark_node;
}
+ if (flag_tm)
+ tm_malloc_replacement (fn);
+
/* If this function was found without using argument dependent
lookup, then we want to ignore any undeclared friend
functions. */
case POSTDECREMENT_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
+ case ABS_EXPR:
return cp_build_unary_op (code, arg1, candidates != 0, complain);
case ARRAY_REF:
static void
conversion_null_warnings (tree totype, tree expr, tree fn, int argnum)
{
- tree t = non_reference (totype);
-
/* Issue warnings about peculiar, but valid, uses of NULL. */
- if (expr == null_node && TREE_CODE (t) != BOOLEAN_TYPE && ARITHMETIC_TYPE_P (t))
+ if (expr == null_node && TREE_CODE (totype) != BOOLEAN_TYPE
+ && ARITHMETIC_TYPE_P (totype))
{
if (fn)
warning_at (input_location, OPT_Wconversion_null,
argnum, fn);
else
warning_at (input_location, OPT_Wconversion_null,
- "converting to non-pointer type %qT from NULL", t);
+ "converting to non-pointer type %qT from NULL", totype);
}
/* Issue warnings if "false" is converted to a NULL pointer */
- else if (expr == boolean_false_node && POINTER_TYPE_P (t))
+ else if (TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE
+ && TYPE_PTR_P (totype))
{
if (fn)
warning_at (input_location, OPT_Wconversion_null,
"of %qD", argnum, fn);
else
warning_at (input_location, OPT_Wconversion_null,
- "converting %<false%> to pointer type %qT", t);
+ "converting %<false%> to pointer type %qT", totype);
}
}
&& convs->kind != ck_user
&& convs->kind != ck_list
&& convs->kind != ck_ambig
- && convs->kind != ck_ref_bind
+ && (convs->kind != ck_ref_bind
+ || convs->user_conv_p)
&& convs->kind != ck_rvalue
&& convs->kind != ck_base)
{
&& BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
permerror (input_location, "too many braces around initializer for %qT", totype);
- for (; t; t = convs->u.next)
+ for (; t ; t = next_conversion (t))
{
if (t->kind == ck_user && t->cand->reason)
{
/*issue_conversion_warnings=*/false,
/*c_cast_p=*/false,
complain);
- return cp_convert (totype, expr);
+ if (convs->kind == ck_ref_bind)
+ return convert_to_reference (totype, expr, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
+ else
+ return cp_convert (totype, expr);
}
else if (t->kind == ck_user || !t->bad_p)
{
&& CONSTRUCTOR_NELTS (expr) == 0
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
{
+ bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
expr = build_value_init (totype, complain);
expr = get_target_expr_sfinae (expr, complain);
if (expr != error_mark_node)
- TARGET_EXPR_LIST_INIT_P (expr) = true;
+ {
+ TARGET_EXPR_LIST_INIT_P (expr) = true;
+ TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
+ }
return expr;
}
/* 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)
+ /* Unless this is for direct-list-initialization. */
+ && !(BRACE_ENCLOSED_INITIALIZER_P (expr)
+ && CONSTRUCTOR_IS_DIRECT_INIT (expr))
/* Unless we're calling it for value-initialization from an
empty list, since that is handled separately in 8.5.4. */
&& cand->num_convs > 0)
leave it as an lvalue. */
if (inner >= 0)
{
- expr = decl_constant_value (expr);
+ expr = decl_constant_value_safe (expr);
if (expr == null_node && INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (totype))
/* If __null has been converted to an integer type, we do not
want to warn about uses of EXPR as an integer, rather than
{
tree ref_type = totype;
- if (convs->bad_p && TYPE_REF_IS_RVALUE (ref_type)
- && real_lvalue_p (expr))
+ if (convs->bad_p && !convs->u.next->bad_p)
{
+ gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
+ && real_lvalue_p (expr));
+
error ("cannot bind %qT lvalue to %qT",
TREE_TYPE (expr), totype);
if (fn)
we must not perform access checks here. */
push_deferring_access_checks (dk_no_check);
+ /* We must make a copy of ARG, in case subsequent processing
+ alters any part of it. */
arg = break_out_target_exprs (arg);
if (TREE_CODE (arg) == CONSTRUCTOR)
{
}
else
{
- /* We must make a copy of ARG, in case subsequent processing
- alters any part of it. For example, during gimplification a
- cast of the form (T) &X::f (where "f" is a member function)
- will lead to replacing the PTRMEM_CST for &X::f with a
- VAR_DECL. We can avoid the copy for constants, since they
- are never modified in place. */
- if (!CONSTANT_CLASS_P (arg))
- arg = unshare_expr (arg);
arg = convert_for_initialization (0, type, arg, LOOKUP_IMPLICIT,
ICR_DEFAULT_ARGUMENT, fn, parmnum,
tf_warning_or_error);
converted_arg = build_base_path (PLUS_EXPR,
arg,
cand->conversion_path,
- 1);
+ 1, complain);
/* Check that the base class is accessible. */
if (!accessible_base_p (TREE_TYPE (argtype),
BINFO_TYPE (cand->conversion_path), true))
base_binfo = lookup_base (TREE_TYPE (TREE_TYPE (converted_arg)),
TREE_TYPE (parmtype), ba_unique, NULL);
converted_arg = build_base_path (PLUS_EXPR, converted_arg,
- base_binfo, 1);
+ base_binfo, 1, complain);
argarray[j++] = converted_arg;
parm = TREE_CHAIN (parm);
if (TREE_DEPRECATED (fn))
warn_deprecated_use (fn, NULL_TREE);
- argarray[0] = build_base_path (PLUS_EXPR, argarray[0], binfo, 1);
+ argarray[0] = build_base_path (PLUS_EXPR, argarray[0], binfo, 1,
+ complain);
if (TREE_SIDE_EFFECTS (argarray[0]))
argarray[0] = save_expr (argarray[0]);
t = build_pointer_type (TREE_TYPE (fn));
fn = build_call_a (fn, nargs, argarray);
SET_EXPR_LOCATION (fn, loc);
- /* If this call might throw an exception, note that fact. */
fndecl = get_callee_fndecl (fn);
/* Check that arguments to builtin functions match the expectations. */
/* However, for assignment operators, we must convert
dynamically if the base is virtual. */
instance = build_base_path (PLUS_EXPR, instance,
- binfo, /*nonnull=*/1);
+ binfo, /*nonnull=*/1, complain);
}
}
current_in_charge_parm, integer_zero_node),
current_vtt_parm,
vtt);
- gcc_assert (BINFO_SUBVTT_INDEX (binfo));
- sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+ if (BINFO_SUBVTT_INDEX (binfo))
+ sub_vtt = fold_build_pointer_plus (vtt, BINFO_SUBVTT_INDEX (binfo));
+ else
+ sub_vtt = vtt;
if (args == NULL)
{
&& CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
{
tree init_list = VEC_index (tree, *args, 0);
+ tree init = NULL_TREE;
gcc_assert (VEC_length (tree, *args) == 1
&& !(flags & LOOKUP_ONLYCONVERTING));
if (CONSTRUCTOR_NELTS (init_list) == 0
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
&& !processing_template_decl)
+ init = build_value_init (basetype, complain);
+
+ /* If BASETYPE is an aggregate, we need to do aggregate
+ initialization. */
+ else if (CP_AGGREGATE_TYPE_P (basetype))
+ init = digest_init (basetype, init_list, complain);
+
+ if (init)
{
- tree ob, init = build_value_init (basetype, complain);
+ tree ob;
if (integer_zerop (instance_ptr))
return get_target_expr_sfinae (init, complain);
ob = build_fold_indirect_ref (instance_ptr);
return init;
}
+ /* Otherwise go ahead with overload resolution. */
add_list_candidates (fns, first_mem_arg, init_list,
basetype, explicit_targs, template_only,
conversion_path, access_binfo, flags, &candidates);
}
else
{
+ /* Optimize away vtable lookup if we know that this function
+ can't be overridden. */
if (DECL_VINDEX (fn) && ! (flags & LOOKUP_NONVIRTUAL)
- && resolves_to_fixed_type_p (instance, 0))
+ && (resolves_to_fixed_type_p (instance, 0)
+ || DECL_FINAL_P (fn) || CLASSTYPE_FINAL (basetype)))
flags |= LOOKUP_NONVIRTUAL;
if (explicit_targs)
flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
types to which the references refer are the same type except for
top-level cv-qualifiers, and the type to which the reference
initialized by S2 refers is more cv-qualified than the type to
- which the reference initialized by S1 refers */
+ which the reference initialized by S1 refers.
+
+ DR 1328 [over.match.best]: the context is an initialization by
+ conversion function for direct reference binding (13.3.1.6) of a
+ reference to function type, the return type of F1 is the same kind of
+ reference (i.e. lvalue or rvalue) as the reference being initialized,
+ and the return type of F2 is not. */
if (ref_conv1 && ref_conv2)
{
- if (!ref_conv1->this_p && !ref_conv2->this_p)
+ if (!ref_conv1->this_p && !ref_conv2->this_p
+ && (ref_conv1->rvaluedness_matches_p
+ != ref_conv2->rvaluedness_matches_p)
+ && (same_type_p (ref_conv1->type, ref_conv2->type)
+ || (TYPE_REF_IS_RVALUE (ref_conv1->type)
+ != TYPE_REF_IS_RVALUE (ref_conv2->type))))
{
- if (ref_conv1->rvaluedness_matches_p
- > ref_conv2->rvaluedness_matches_p)
- return 1;
- if (ref_conv2->rvaluedness_matches_p
- > ref_conv1->rvaluedness_matches_p)
- return -1;
+ return (ref_conv1->rvaluedness_matches_p
+ - ref_conv2->rvaluedness_matches_p);
}
if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
if (winner)
return winner;
+ /* DR 495 moved this tiebreaker above the template ones. */
+ /* or, if not that,
+ the context is an initialization by user-defined conversion (see
+ _dcl.init_ and _over.match.user_) and the standard conversion
+ sequence from the return type of F1 to the destination type (i.e.,
+ the type of the entity being initialized) is a better conversion
+ sequence than the standard conversion sequence from the return type
+ of F2 to the destination type. */
+
+ if (cand1->second_conv)
+ {
+ winner = compare_ics (cand1->second_conv, cand2->second_conv);
+ if (winner)
+ return winner;
+ }
+
/* or, if not that,
F1 is a non-template function and F2 is a template function
specialization. */
return winner;
}
- /* or, if not that,
- the context is an initialization by user-defined conversion (see
- _dcl.init_ and _over.match.user_) and the standard conversion
- sequence from the return type of F1 to the destination type (i.e.,
- the type of the entity being initialized) is a better conversion
- sequence than the standard conversion sequence from the return type
- of F2 to the destination type. */
-
- if (cand1->second_conv)
- {
- winner = compare_ics (cand1->second_conv, cand2->second_conv);
- if (winner)
- return winner;
- }
-
/* Check whether we can discard a builtin candidate, either because we
have two identical ones or matching builtin and non-builtin candidates.
}
expr = error_mark_node;
}
- else if (processing_template_decl)
+ else if (processing_template_decl && conv->kind != ck_identity)
{
/* In a template, we are only concerned about determining the
type of non-dependent expressions, so we do not have to
- perform the actual conversion. */
- if (TREE_TYPE (expr) != type)
- expr = build_nop (type, expr);
+ perform the actual conversion. But for initializers, we
+ need to be able to perform it at instantiation
+ (or fold_non_dependent_expr) time. */
+ expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
+ if (!(flags & LOOKUP_ONLYCONVERTING))
+ IMPLICIT_CONV_EXPR_DIRECT_INIT (expr) = true;
}
else
expr = convert_like (conv, expr, complain);
return expr;
}
+/* When initializing a reference that lasts longer than a full-expression,
+ this special rule applies:
+
+ [class.temporary]
+
+ The temporary to which the reference is bound or the temporary
+ that is the complete object to which the reference is bound
+ persists for the lifetime of the reference.
+
+ The temporaries created during the evaluation of the expression
+ initializing the reference, except the temporary to which the
+ reference is bound, are destroyed at the end of the
+ full-expression in which they are created.
+
+ In that case, we store the converted expression into a new
+ VAR_DECL in a new scope.
+
+ However, we want to be careful not to create temporaries when
+ they are not required. For example, given:
+
+ struct B {};
+ struct D : public B {};
+ D f();
+ const B& b = f();
+
+ there is no need to copy the return value from "f"; we can just
+ extend its lifetime. Similarly, given:
+
+ struct S {};
+ struct T { operator S(); };
+ T t;
+ const S& s = t;
+
+ we can extend the lifetime of the return value of the conversion
+ operator.
+
+ The next several functions are involved in this lifetime extension. */
+
/* DECL is a VAR_DECL whose type is a REFERENCE_TYPE. The reference
is being bound to a temporary. Create and return a new VAR_DECL
with the indicated TYPE; this variable will store the value to
if (TREE_STATIC (decl))
{
/* Namespace-scope or local static; give it a mangled name. */
+ /* FIXME share comdat with decl? */
tree name;
TREE_STATIC (var) = 1;
cleanup for the new variable is returned through CLEANUP, and the
code to initialize the new variable is returned through INITP. */
-tree
-set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
+static tree
+set_up_extended_ref_temp (tree decl, tree expr, VEC(tree,gc) **cleanups,
+ tree *initp)
{
tree init;
tree type;
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
+ if (TREE_CODE (decl) == FIELD_DECL
+ && extra_warnings && !TREE_NO_WARNING (decl))
+ {
+ warning (OPT_Wextra, "a temporary bound to %qD only persists "
+ "until the constructor exits", decl);
+ TREE_NO_WARNING (decl) = true;
+ }
+
+ /* Recursively extend temps in this initializer. */
+ TARGET_EXPR_INITIAL (expr)
+ = extend_ref_init_temps (decl, TARGET_EXPR_INITIAL (expr), cleanups);
+
/* If the initializer is constant, put it in DECL_INITIAL so we get
static initialization and use in constant expressions. */
init = maybe_constant_init (expr);
if (TREE_STATIC (var))
init = add_stmt_to_compound (init, register_dtor_fn (var));
else
- *cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
+ {
+ tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
+ if (cleanup)
+ VEC_safe_push (tree, gc, *cleanups, cleanup);
+ }
/* We must be careful to destroy the temporary only
after its initialization has taken place. If the
}
/* Convert EXPR to the indicated reference TYPE, in a way suitable for
- initializing a variable of that TYPE. If DECL is non-NULL, it is
- the VAR_DECL being initialized with the EXPR. (In that case, the
- type of DECL will be TYPE.) If DECL is non-NULL, then CLEANUP must
- also be non-NULL, and with *CLEANUP initialized to NULL. Upon
- return, if *CLEANUP is no longer NULL, it will be an expression
- that should be pushed as a cleanup after the returned expression
- is used to initialize DECL.
-
- Return the converted expression. */
+ initializing a variable of that TYPE. */
tree
-initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
+initialize_reference (tree type, tree expr,
int flags, tsubst_flags_t complain)
{
conversion *conv;
{
if (complain & tf_error)
{
- if (!CP_TYPE_CONST_P (TREE_TYPE (type))
- && !TYPE_REF_IS_RVALUE (type)
- && !real_lvalue_p (expr))
+ if (conv)
+ convert_like (conv, expr, complain);
+ else if (!CP_TYPE_CONST_P (TREE_TYPE (type))
+ && !TYPE_REF_IS_RVALUE (type)
+ && !real_lvalue_p (expr))
error ("invalid initialization of non-const reference of "
"type %qT from an rvalue of type %qT",
type, TREE_TYPE (expr));
return error_mark_node;
}
- /* If DECL is non-NULL, then this special rule applies:
-
- [class.temporary]
-
- The temporary to which the reference is bound or the temporary
- that is the complete object to which the reference is bound
- persists for the lifetime of the reference.
+ gcc_assert (conv->kind == ck_ref_bind);
- The temporaries created during the evaluation of the expression
- initializing the reference, except the temporary to which the
- reference is bound, are destroyed at the end of the
- full-expression in which they are created.
+ /* Perform the conversion. */
+ expr = convert_like (conv, expr, complain);
- In that case, we store the converted expression into a new
- VAR_DECL in a new scope.
+ /* Free all the conversions we allocated. */
+ obstack_free (&conversion_obstack, p);
- However, we want to be careful not to create temporaries when
- they are not required. For example, given:
+ return expr;
+}
- struct B {};
- struct D : public B {};
- D f();
- const B& b = f();
+/* Subroutine of extend_ref_init_temps. Possibly extend one initializer,
+ which is bound either to a reference or a std::initializer_list. */
- there is no need to copy the return value from "f"; we can just
- extend its lifetime. Similarly, given:
+static tree
+extend_ref_init_temps_1 (tree decl, tree init, VEC(tree,gc) **cleanups)
+{
+ tree sub = init;
+ tree *p;
+ STRIP_NOPS (sub);
+ if (TREE_CODE (sub) != ADDR_EXPR)
+ return init;
+ /* Deal with binding to a subobject. */
+ for (p = &TREE_OPERAND (sub, 0); TREE_CODE (*p) == COMPONENT_REF; )
+ p = &TREE_OPERAND (*p, 0);
+ if (TREE_CODE (*p) == TARGET_EXPR)
+ {
+ tree subinit = NULL_TREE;
+ *p = set_up_extended_ref_temp (decl, *p, cleanups, &subinit);
+ if (subinit)
+ init = build2 (COMPOUND_EXPR, TREE_TYPE (init), subinit, init);
+ }
+ return init;
+}
- struct S {};
- struct T { operator S(); };
- T t;
- const S& s = t;
+/* INIT is part of the initializer for DECL. If there are any
+ reference or initializer lists being initialized, extend their
+ lifetime to match that of DECL. */
- we can extend the lifetime of the return value of the conversion
- operator. */
- gcc_assert (conv->kind == ck_ref_bind);
- if (decl)
+tree
+extend_ref_init_temps (tree decl, tree init, VEC(tree,gc) **cleanups)
+{
+ tree type = TREE_TYPE (init);
+ if (processing_template_decl)
+ return init;
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ init = extend_ref_init_temps_1 (decl, init, cleanups);
+ else if (is_std_init_list (type))
{
- tree var;
- tree base_conv_type;
-
- gcc_assert (complain == tf_warning_or_error);
-
- /* Skip over the REF_BIND. */
- conv = conv->u.next;
- /* If the next conversion is a BASE_CONV, skip that too -- but
- remember that the conversion was required. */
- if (conv->kind == ck_base)
- {
- base_conv_type = conv->type;
- conv = conv->u.next;
- }
- else
- base_conv_type = NULL_TREE;
- /* Perform the remainder of the conversion. */
- expr = convert_like_real (conv, expr,
- /*fn=*/NULL_TREE, /*argnum=*/0,
- /*inner=*/-1,
- /*issue_conversion_warnings=*/true,
- /*c_cast_p=*/false,
- complain);
- if (error_operand_p (expr))
- expr = error_mark_node;
- 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)
{
- if (!lvalue_or_rvalue_with_address_p (expr))
- {
- tree init;
- var = set_up_extended_ref_temp (decl, expr, cleanup, &init);
- /* Use its address to initialize the reference variable. */
- expr = build_address (var);
- if (base_conv_type)
- expr = convert_to_base (expr,
- build_pointer_type (base_conv_type),
- /*check_access=*/true,
- /*nonnull=*/true, complain);
- if (init)
- expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
- }
- else
- /* Take the address of EXPR. */
- expr = cp_build_addr_expr (expr, complain);
- /* If a BASE_CONV was required, perform it now. */
- if (base_conv_type)
- expr = (perform_implicit_conversion
- (build_pointer_type (base_conv_type), expr,
- complain));
- expr = build_nop (type, expr);
+ tree array = CONSTRUCTOR_ELT (ctor, 0)->value;
+ array = extend_ref_init_temps_1 (decl, array, cleanups);
+ CONSTRUCTOR_ELT (ctor, 0)->value = array;
}
}
- else
- /* Perform the conversion. */
- expr = convert_like (conv, expr, complain);
-
- /* Free all the conversions we allocated. */
- obstack_free (&conversion_obstack, p);
+ else if (TREE_CODE (init) == CONSTRUCTOR)
+ {
+ unsigned i;
+ constructor_elt *p;
+ VEC(constructor_elt,gc) *elts = CONSTRUCTOR_ELTS (init);
+ FOR_EACH_VEC_ELT (constructor_elt, elts, i, p)
+ p->value = extend_ref_init_temps (decl, p->value, cleanups);
+ }
- return expr;
+ return init;
}
/* Returns true iff TYPE is some variant of std::initializer_list. */