re PR c++/48370 (G++ fails to extend reference temporary lifetime in some situations)

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.

From-SVN: r180944
This commit is contained in:
Jason Merrill 2011-11-04 08:54:08 -04:00 committed by Jason Merrill
parent 5972791c34
commit b25dd954c4
16 changed files with 315 additions and 198 deletions

View File

@ -1,3 +1,26 @@
2011-11-04 Jason Merrill <jason@redhat.com>
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.
2011-11-02 Jason Merrill <jason@redhat.com>
PR c++/50930

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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. */

View File

@ -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,

View File

@ -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);
}

View File

@ -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)

View File

@ -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. */

View File

@ -1,3 +1,11 @@
2011-11-04 Jason Merrill <jason@redhat.com>
PR c++/48370
* g++.dg/cpp0x/initlist-lifetime1.C: New.
* g++.dg/init/lifetime1.C: New.
* g++.dg/init/ref21.C: New.
* g++.dg/eh/array1.C: New.
2011-11-04 Tom de Vries <tom@codesourcery.com>
PR tree-optimization/50763

View File

@ -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;
}

View File

@ -0,0 +1,15 @@
// 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] = { };
}

View File

@ -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;
}

View File

@ -0,0 +1,7 @@
struct A
{
const int &i1;
const int &i2;
};
A a = { 1, 2 };

View File

@ -1,3 +1,9 @@
2011-11-04 Jason Merrill <jason@redhat.com>
PR c++/48370
* cp-demangle.c (d_special_name, d_print_comp): Handle a
discriminator number on DEMANGLE_COMPONENT_REFTEMP.
2011-11-02 Doug Evans <dje@google.com>
* Makefile.in (CFILES): Add timeval-utils.c.

View File

@ -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;