mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-02 08:40:26 +08:00
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:
parent
5972791c34
commit
b25dd954c4
@ -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
|
||||
|
220
gcc/cp/call.c
220
gcc/cp/call.c
@ -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);
|
||||
|
114
gcc/cp/decl.c
114
gcc/cp/decl.c
@ -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. */
|
||||
|
@ -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
|
||||
|
34
gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C
Normal file
34
gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C
Normal 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;
|
||||
}
|
15
gcc/testsuite/g++.dg/eh/array1.C
Normal file
15
gcc/testsuite/g++.dg/eh/array1.C
Normal 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] = { };
|
||||
}
|
29
gcc/testsuite/g++.dg/init/lifetime1.C
Normal file
29
gcc/testsuite/g++.dg/init/lifetime1.C
Normal 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;
|
||||
}
|
7
gcc/testsuite/g++.dg/init/ref21.C
Normal file
7
gcc/testsuite/g++.dg/init/ref21.C
Normal file
@ -0,0 +1,7 @@
|
||||
struct A
|
||||
{
|
||||
const int &i1;
|
||||
const int &i2;
|
||||
};
|
||||
|
||||
A a = { 1, 2 };
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user