commit 82e649dc7b7918d48b14a88dc2fda9836e421cd9 Author: Jason Merrill 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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ce8933a..4d7facc 100644 --- a/gcc/cp/call.c +++ b/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 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ac42e0e..dc52d29 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index edbc783..50c45de 100644 --- a/gcc/cp/decl.c +++ b/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 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 %", 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; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index be9044b..32b5c7e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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. */ diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ec7ba0e..3881275 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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, diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 69fe147..7c907b8 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -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); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 0b1f217..58bb14f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -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) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 1b43449..70edc2f 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -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. */ diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C new file mode 100644 index 0000000..e43ce5d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-lifetime1.C @@ -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 + +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 AL; +typedef std::initializer_list AL2; +typedef std::initializer_list 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; +} diff --git a/gcc/testsuite/g++.dg/eh/array1.C b/gcc/testsuite/g++.dg/eh/array1.C new file mode 100644 index 0000000..ceb9824 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/array1.C @@ -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] = { }; +} + diff --git a/gcc/testsuite/g++.dg/init/lifetime1.C b/gcc/testsuite/g++.dg/init/lifetime1.C new file mode 100644 index 0000000..38e25ec --- /dev/null +++ b/gcc/testsuite/g++.dg/init/lifetime1.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/init/ref21.C b/gcc/testsuite/g++.dg/init/ref21.C new file mode 100644 index 0000000..db4ac4a --- /dev/null +++ b/gcc/testsuite/g++.dg/init/ref21.C @@ -0,0 +1,7 @@ +struct A +{ + const int &i1; + const int &i2; +}; + +A a = { 1, 2 }; diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index c7afef0..d0f57b7 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.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;