commit 82e649dc7b7918d48b14a88dc2fda9836e421cd9
Author: Jason Merrill <jason@redhat.com>
Date: Sat Oct 22 11:40:16 2011 -0400
PR c++/48370
* call.c (extend_ref_init_temps, extend_ref_init_temps_1): New.
(set_up_extended_ref_temp): Use it. Change cleanup parm to VEC.
(initialize_reference): Just call convert_like.
* decl.c (grok_reference_init): Just call initialize_reference.
(build_init_list_var_init): Remove.
(check_initializer): Change cleanup parm to VEC. Handle references
like other types. Call perform_implicit_conversion instead
of build_init_list_var_init. Don't use build_aggr_init for
aggregate initialization of arrays.
(cp_finish_decl): Change cleanup to VEC.
* typeck2.c (store_init_value): Call extend_ref_init_temps.
Use build_vec_init for non-constant arrays.
* init.c (expand_aggr_init_1): Adjust.
(build_vec_init): Avoid re-converting an initializer
that's already digested.
* mangle.c (mangle_ref_init_variable): Add a discriminator.
* cp-tree.h: Adjust.
* typeck.c (convert_for_initialization): Adjust.
* decl2.c (maybe_emit_vtables): Adjust.
@@ -8502,6 +8502,44 @@ perform_direct_initialization_if_possible (tree type,
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
@@ -8519,6 +8557,7 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
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;
@@ -8540,8 +8579,9 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
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;
@@ -8562,6 +8602,10 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
+ /* 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);
@@ -8595,7 +8639,11 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
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
@@ -8629,18 +8677,10 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
}
/* 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;
@@ -8674,98 +8714,10 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
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.
-
- 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. */
gcc_assert (conv->kind == ck_ref_bind);
- if (decl)
- {
- 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
- {
- 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);
- }
- }
- else
- /* Perform the conversion. */
- expr = convert_like (conv, expr, complain);
+ /* Perform the conversion. */
+ expr = convert_like (conv, expr, complain);
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
@@ -8773,6 +8725,68 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
return expr;
}
+/* Subroutine of extend_ref_init_temps. Possibly extend one initializer,
+ which is bound either to a reference or a std::initializer_list. */
+
+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;
+}
+
+/* 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. */
+
+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))
+ {
+ /* 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;
+ }
+ }
+ 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 init;
+}
+
/* Returns true iff TYPE is some variant of std::initializer_list. */
bool
@@ -4810,9 +4810,9 @@ extern tree cxx_type_promotes_to (tree);
extern tree type_passed_as (tree);
extern tree convert_for_arg_passing (tree, tree);
extern bool is_properly_derived_from (tree, tree);
-extern tree set_up_extended_ref_temp (tree, tree, tree *, tree *);
-extern tree initialize_reference (tree, tree, tree, tree *, int,
+extern tree initialize_reference (tree, tree, int,
tsubst_flags_t);
+extern tree extend_ref_init_temps (tree, tree, VEC(tree,gc)**);
extern tree make_temporary_var_for_ref_to_temp (tree, tree);
extern tree strip_top_quals (tree);
extern bool reference_related_p (tree, tree);
@@ -5793,7 +5793,7 @@ extern void complete_type_check_abstract (tree);
extern int abstract_virtuals_error (tree, tree);
extern int abstract_virtuals_error_sfinae (tree, tree, tsubst_flags_t);
-extern tree store_init_value (tree, tree, int);
+extern tree store_init_value (tree, tree, VEC(tree,gc)**, int);
extern void check_narrowing (tree, tree);
extern tree digest_init (tree, tree, tsubst_flags_t);
extern tree digest_init_flags (tree, tree, int);
@@ -71,7 +71,7 @@ static void require_complete_types_for_parms (tree);
static int ambi_op_p (enum tree_code);
static int unary_op_p (enum tree_code);
static void push_local_name (tree);
-static tree grok_reference_init (tree, tree, tree, tree *, int);
+static tree grok_reference_init (tree, tree, tree, int);
static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *,
int, int, tree);
static int check_static_variable_definition (tree, tree);
@@ -91,7 +91,7 @@ static tree lookup_and_check_tag (enum tag_types, tree, tag_scope, bool);
static int walk_namespaces_r (tree, walk_namespaces_fn, void *);
static void maybe_deduce_size_from_array_init (tree, tree);
static void layout_var_decl (tree);
-static tree check_initializer (tree, tree, int, tree *);
+static tree check_initializer (tree, tree, int, VEC(tree,gc) **);
static void make_rtl_for_nonlocal_decl (tree, tree, const char *);
static void save_function_data (tree);
static void copy_type_enum (tree , tree);
@@ -4611,11 +4611,8 @@ start_decl_1 (tree decl, bool initialized)
Quotes on semantics can be found in ARM 8.4.3. */
static tree
-grok_reference_init (tree decl, tree type, tree init, tree *cleanup,
- int flags)
+grok_reference_init (tree decl, tree type, tree init, int flags)
{
- tree tmp;
-
if (init == NULL_TREE)
{
if ((DECL_LANG_SPECIFIC (decl) == 0
@@ -4641,62 +4638,8 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup,
DECL_INITIAL for local references (instead assigning to them
explicitly); we need to allow the temporary to be initialized
first. */
- tmp = initialize_reference (type, init, decl, cleanup, flags,
- tf_warning_or_error);
- if (DECL_DECLARED_CONSTEXPR_P (decl))
- {
- tmp = cxx_constant_value (tmp);
- DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
- = reduced_constant_expression_p (tmp);
- }
-
- if (tmp == error_mark_node)
- return NULL_TREE;
- else if (tmp == NULL_TREE)
- {
- error ("cannot initialize %qT from %qT", type, TREE_TYPE (init));
- return NULL_TREE;
- }
-
- if (TREE_STATIC (decl) && !TREE_CONSTANT (tmp))
- return tmp;
-
- DECL_INITIAL (decl) = tmp;
-
- return NULL_TREE;
-}
-
-/* Subroutine of check_initializer. We're initializing a DECL of
- std::initializer_list<T> TYPE from a braced-init-list INIT, and need to
- extend the lifetime of the underlying array to match that of the decl,
- just like for reference initialization. CLEANUP is as for
- grok_reference_init. */
-
-static tree
-build_init_list_var_init (tree decl, tree type, tree init, tree *array_init,
- tree *cleanup)
-{
- tree aggr_init, array, arrtype;
- init = perform_implicit_conversion (type, init, tf_warning_or_error);
- if (error_operand_p (init))
- return error_mark_node;
-
- aggr_init = TARGET_EXPR_INITIAL (init);
- array = CONSTRUCTOR_ELT (aggr_init, 0)->value;
- arrtype = TREE_TYPE (array);
- STRIP_NOPS (array);
- gcc_assert (TREE_CODE (array) == ADDR_EXPR);
- array = TREE_OPERAND (array, 0);
- /* If the array is constant, finish_compound_literal already made it a
- static variable and we don't need to do anything here. */
- if (decl && TREE_CODE (array) == TARGET_EXPR)
- {
- tree var = set_up_extended_ref_temp (decl, array, cleanup, array_init);
- var = build_address (var);
- var = convert (arrtype, var);
- CONSTRUCTOR_ELT (aggr_init, 0)->value = var;
- }
- return init;
+ return initialize_reference (type, init, flags,
+ tf_warning_or_error);
}
/* Designated initializers in arrays are not supported in GNU C++.
@@ -5440,7 +5383,7 @@ build_aggr_init_full_exprs (tree decl, tree init, int flags)
evaluated dynamically to initialize DECL. */
static tree
-check_initializer (tree decl, tree init, int flags, tree *cleanup)
+check_initializer (tree decl, tree init, int flags, VEC(tree,gc) **cleanups)
{
tree type = TREE_TYPE (decl);
tree init_code = NULL;
@@ -5509,19 +5452,26 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
}
else if (!init && DECL_REALLY_EXTERN (decl))
;
- else if (TREE_CODE (type) == REFERENCE_TYPE)
- init = grok_reference_init (decl, type, init, cleanup, flags);
- else if (init || type_build_ctor_call (type))
+ else if (init || type_build_ctor_call (type)
+ || TREE_CODE (type) == REFERENCE_TYPE)
{
- if (!init)
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ init = grok_reference_init (decl, type, init, flags);
+ flags |= LOOKUP_ALREADY_DIGESTED;
+ }
+ else if (!init)
check_for_uninitialized_const_var (decl);
/* Do not reshape constructors of vectors (they don't need to be
reshaped. */
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
{
if (is_std_init_list (type))
- init = build_init_list_var_init (decl, type, init,
- &extra_init, cleanup);
+ {
+ init = perform_implicit_conversion (type, init,
+ tf_warning_or_error);
+ flags |= LOOKUP_ALREADY_DIGESTED;
+ }
else if (TYPE_NON_AGGREGATE_CLASS (type))
{
/* Don't reshape if the class has constructors. */
@@ -5550,9 +5500,10 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
if (type == error_mark_node)
return NULL_TREE;
- if (type_build_ctor_call (type)
- || (CLASS_TYPE_P (type)
- && !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
+ if ((type_build_ctor_call (type) || CLASS_TYPE_P (type))
+ && !(flags & LOOKUP_ALREADY_DIGESTED)
+ && !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CP_AGGREGATE_TYPE_P (type)))
{
init_code = build_aggr_init_full_exprs (decl, init, flags);
@@ -5594,7 +5545,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
if (init && TREE_CODE (init) != TREE_VEC)
{
- init_code = store_init_value (decl, init, flags);
+ init_code = store_init_value (decl, init, cleanups, flags);
if (pedantic && TREE_CODE (type) == ARRAY_TYPE
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
@@ -5956,7 +5907,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
tree asmspec_tree, int flags)
{
tree type;
- tree cleanup;
+ VEC(tree,gc) *cleanups = NULL;
const char *asmspec = NULL;
int was_readonly = 0;
bool var_definition_p = false;
@@ -5979,9 +5930,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (type == error_mark_node)
return;
- /* Assume no cleanup is required. */
- cleanup = NULL_TREE;
-
/* If a name was specified, get the string. */
if (at_namespace_scope_p ())
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
@@ -6101,7 +6049,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* This variable seems to be a non-dependent constant, so process
its initializer. If check_initializer returns non-null the
initialization wasn't constant after all. */
- tree init_code = check_initializer (decl, init, flags, &cleanup);
+ tree init_code = check_initializer (decl, init, flags, &cleanups);
if (init_code == NULL_TREE)
init = NULL_TREE;
}
@@ -6202,7 +6150,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
error ("Java object %qD not allocated with %<new%>", decl);
init = NULL_TREE;
}
- init = check_initializer (decl, init, flags, &cleanup);
+ init = check_initializer (decl, init, flags, &cleanups);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL_P (decl) && init)
{
@@ -6367,8 +6315,12 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
reference, insert it in the statement-tree now. */
- if (cleanup)
- push_cleanup (decl, cleanup, false);
+ if (cleanups)
+ {
+ unsigned i; tree t;
+ FOR_EACH_VEC_ELT_REVERSE (tree, cleanups, i, t)
+ push_cleanup (decl, t, false);
+ }
if (was_readonly)
TREE_READONLY (decl) = 1;
@@ -1877,10 +1877,12 @@ maybe_emit_vtables (tree ctype)
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
{
- tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), LOOKUP_NORMAL);
+ VEC(tree,gc)* cleanups = NULL;
+ tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), &cleanups,
+ LOOKUP_NORMAL);
/* It had better be all done at compile-time. */
- gcc_assert (!expr);
+ gcc_assert (!expr && !cleanups);
}
/* Write it out. */
@@ -1597,12 +1597,14 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
if (init && TREE_CODE (exp) == VAR_DECL
&& COMPOUND_LITERAL_P (init))
{
+ VEC(tree,gc)* cleanups = NULL;
/* If store_init_value returns NULL_TREE, the INIT has been
recorded as the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */
- init = store_init_value (exp, init, flags);
+ init = store_init_value (exp, init, &cleanups, flags);
if (init)
finish_expr_stmt (init);
+ gcc_assert (!cleanups);
return;
}
@@ -3150,6 +3152,9 @@ build_vec_init (tree base, tree maxindex, tree init,
bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
&& (literal_type_p (inner_elt_type)
|| TYPE_HAS_CONSTEXPR_CTOR (inner_elt_type)));
+ /* If the constructor already has the array type, it's been through
+ digest_init, so we shouldn't try to do anything more. */
+ bool digested = same_type_p (atype, TREE_TYPE (init));
bool saw_non_const = false;
bool saw_const = false;
/* If we're initializing a static array, we want to do static
@@ -3172,7 +3177,9 @@ build_vec_init (tree base, tree maxindex, tree init,
num_initialized_elts++;
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
- if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
+ if (digested)
+ one_init = build2 (INIT_EXPR, type, baseref, elt);
+ else if (MAYBE_CLASS_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
one_init = build_aggr_init (baseref, elt, 0, complain);
else
one_init = cp_build_modify_expr (baseref, NOP_EXPR,
@@ -3503,12 +3503,17 @@ mangle_guard_variable (const tree variable)
initialize a static reference. This isn't part of the ABI, but we might
as well call them something readable. */
+static GTY(()) int temp_count;
+
tree
mangle_ref_init_variable (const tree variable)
{
start_mangling (variable);
write_string ("_ZGR");
write_name (variable, /*ignore_local_scope=*/0);
+ /* Avoid name clashes with aggregate initialization of multiple
+ references at once. */
+ write_unsigned_number (temp_count++);
return finish_mangling_get_identifier (/*warn=*/false);
}
@@ -7561,8 +7561,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
if (fndecl)
savew = warningcount, savee = errorcount;
- rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
- /*cleanup=*/NULL, flags, complain);
+ rhs = initialize_reference (type, rhs, flags, complain);
if (fndecl)
{
if (warningcount > savew)
@@ -655,7 +655,7 @@ split_nonconstant_init (tree dest, tree init)
for static variable. In that case, caller must emit the code. */
tree
-store_init_value (tree decl, tree init, int flags)
+store_init_value (tree decl, tree init, VEC(tree,gc)** cleanups, int flags)
{
tree value, type;
@@ -699,6 +699,8 @@ store_init_value (tree decl, tree init, int flags)
/* Digest the specified initializer into an expression. */
value = digest_init_flags (type, init, flags);
+ value = extend_ref_init_temps (decl, value, cleanups);
+
/* In C++0x constant expression is a semantic, not syntactic, property.
In C++98, make sure that what we thought was a constant expression at
template definition time is still constant. */
@@ -725,7 +727,16 @@ store_init_value (tree decl, tree init, int flags)
if (value != error_mark_node
&& (TREE_SIDE_EFFECTS (value)
|| ! initializer_constant_valid_p (value, TREE_TYPE (value))))
- return split_nonconstant_init (decl, value);
+ {
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (type)))
+ /* For an array, we only need/want a single cleanup region rather
+ than one per element. */
+ return build_vec_init (decl, NULL_TREE, value, false, 1,
+ tf_warning_or_error);
+ else
+ return split_nonconstant_init (decl, value);
+ }
/* If the value is a constant, just put it in DECL_INITIAL. If DECL
is an automatic variable, the middle end will turn this into a
dynamic initialization later. */
new file mode 100644
@@ -0,0 +1,34 @@
+// Test that we properly extend the lifetime of the initializer_list
+// array even if the initializer_list is a subobject.
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+#include <initializer_list>
+
+extern "C" void abort();
+bool ok;
+
+bool do_throw;
+
+struct A {
+ A(int) { if (do_throw) throw 42; }
+ ~A() { if (!ok) abort(); }
+};
+
+typedef std::initializer_list<A> AL;
+typedef std::initializer_list<AL> AL2;
+typedef std::initializer_list<AL2> AL3;
+
+struct B {
+ AL al;
+ const AL& alr;
+};
+
+int main(int argc, const char** argv)
+{
+ do_throw = (argc > 1); // always false, but optimizer can't tell
+ AL ar[] = {{1,2},{3,4}};
+ B b = {{5,6},{7,8}};
+ AL3 al3 = {{{1},{2},{3}}};
+ ok = true;
+}
new file mode 100644
@@ -0,0 +1,16 @@
+// Test that we have one EH cleanup region for the whole array
+// rather than one for each element.
+// { dg-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-times "catch" 1 "gimple" } }
+
+struct A
+{
+ A();
+ ~A();
+};
+
+void f()
+{
+ A a[10] = { };
+}
+
new file mode 100644
@@ -0,0 +1,29 @@
+// PR c++/48370
+// { dg-do run }
+
+extern "C" void abort();
+bool ok;
+
+struct A {
+ int i;
+ A(int i): i(i) { }
+ ~A() { if (!ok) abort(); }
+};
+
+struct D { int i; };
+
+struct B: D, A { B(int i): A(i) { } };
+struct E: D, virtual A { E(int i): A(i) { } };
+
+struct C
+{
+ const A& ar1;
+ const A& ar2;
+ const A& ar3;
+};
+
+int main()
+{
+ C c = { 1, B(2), E(3) };
+ ok = true;
+}
new file mode 100644
@@ -0,0 +1,7 @@
+struct A
+{
+ const int &i1;
+ const int &i2;
+};
+
+A a = { 1, 2 };
@@ -1846,8 +1846,11 @@ d_special_name (struct d_info *di)
return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
case 'R':
- return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
- NULL);
+ {
+ struct demangle_component *name = d_name (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
+ d_number_component (di));
+ }
case 'A':
return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
@@ -3921,7 +3924,9 @@ d_print_comp (struct d_print_info *dpi, int options,
return;
case DEMANGLE_COMPONENT_REFTEMP:
- d_append_string (dpi, "reference temporary for ");
+ d_append_string (dpi, "reference temporary #");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_string (dpi, " for ");
d_print_comp (dpi, options, d_left (dc));
return;