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
16 changed files with 315 additions and 198 deletions
|
@ -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>
|
2011-11-02 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
PR c++/50930
|
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;
|
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
|
/* 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
|
is being bound to a temporary. Create and return a new VAR_DECL
|
||||||
with the indicated TYPE; this variable will store the value to
|
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))
|
if (TREE_STATIC (decl))
|
||||||
{
|
{
|
||||||
/* Namespace-scope or local static; give it a mangled name. */
|
/* Namespace-scope or local static; give it a mangled name. */
|
||||||
|
/* FIXME share comdat with decl? */
|
||||||
tree name;
|
tree name;
|
||||||
|
|
||||||
TREE_STATIC (var) = 1;
|
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
|
cleanup for the new variable is returned through CLEANUP, and the
|
||||||
code to initialize the new variable is returned through INITP. */
|
code to initialize the new variable is returned through INITP. */
|
||||||
|
|
||||||
tree
|
static tree
|
||||||
set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
|
set_up_extended_ref_temp (tree decl, tree expr, VEC(tree,gc) **cleanups,
|
||||||
|
tree *initp)
|
||||||
{
|
{
|
||||||
tree init;
|
tree init;
|
||||||
tree type;
|
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)
|
if (TREE_CODE (expr) != TARGET_EXPR)
|
||||||
expr = get_target_expr (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
|
/* If the initializer is constant, put it in DECL_INITIAL so we get
|
||||||
static initialization and use in constant expressions. */
|
static initialization and use in constant expressions. */
|
||||||
init = maybe_constant_init (expr);
|
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))
|
if (TREE_STATIC (var))
|
||||||
init = add_stmt_to_compound (init, register_dtor_fn (var));
|
init = add_stmt_to_compound (init, register_dtor_fn (var));
|
||||||
else
|
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
|
/* We must be careful to destroy the temporary only
|
||||||
after its initialization has taken place. If the
|
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
|
/* 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
|
initializing a variable of that TYPE. */
|
||||||
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. */
|
|
||||||
|
|
||||||
tree
|
tree
|
||||||
initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
|
initialize_reference (tree type, tree expr,
|
||||||
int flags, tsubst_flags_t complain)
|
int flags, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
conversion *conv;
|
conversion *conv;
|
||||||
|
@ -8674,98 +8714,10 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
|
||||||
return error_mark_node;
|
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);
|
gcc_assert (conv->kind == ck_ref_bind);
|
||||||
if (decl)
|
|
||||||
{
|
|
||||||
tree var;
|
|
||||||
tree base_conv_type;
|
|
||||||
|
|
||||||
gcc_assert (complain == tf_warning_or_error);
|
/* Perform the conversion. */
|
||||||
|
expr = convert_like (conv, expr, complain);
|
||||||
/* 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);
|
|
||||||
|
|
||||||
/* Free all the conversions we allocated. */
|
/* Free all the conversions we allocated. */
|
||||||
obstack_free (&conversion_obstack, p);
|
obstack_free (&conversion_obstack, p);
|
||||||
|
@ -8773,6 +8725,68 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
|
||||||
return expr;
|
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. */
|
/* Returns true iff TYPE is some variant of std::initializer_list. */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -4810,9 +4810,9 @@ extern tree cxx_type_promotes_to (tree);
|
||||||
extern tree type_passed_as (tree);
|
extern tree type_passed_as (tree);
|
||||||
extern tree convert_for_arg_passing (tree, tree);
|
extern tree convert_for_arg_passing (tree, tree);
|
||||||
extern bool is_properly_derived_from (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, int,
|
||||||
extern tree initialize_reference (tree, tree, tree, tree *, int,
|
|
||||||
tsubst_flags_t);
|
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 make_temporary_var_for_ref_to_temp (tree, tree);
|
||||||
extern tree strip_top_quals (tree);
|
extern tree strip_top_quals (tree);
|
||||||
extern bool reference_related_p (tree, 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 (tree, tree);
|
||||||
extern int abstract_virtuals_error_sfinae (tree, tree, tsubst_flags_t);
|
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 void check_narrowing (tree, tree);
|
||||||
extern tree digest_init (tree, tree, tsubst_flags_t);
|
extern tree digest_init (tree, tree, tsubst_flags_t);
|
||||||
extern tree digest_init_flags (tree, tree, int);
|
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 ambi_op_p (enum tree_code);
|
||||||
static int unary_op_p (enum tree_code);
|
static int unary_op_p (enum tree_code);
|
||||||
static void push_local_name (tree);
|
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 *,
|
static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *,
|
||||||
int, int, tree);
|
int, int, tree);
|
||||||
static int check_static_variable_definition (tree, 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 int walk_namespaces_r (tree, walk_namespaces_fn, void *);
|
||||||
static void maybe_deduce_size_from_array_init (tree, tree);
|
static void maybe_deduce_size_from_array_init (tree, tree);
|
||||||
static void layout_var_decl (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 make_rtl_for_nonlocal_decl (tree, tree, const char *);
|
||||||
static void save_function_data (tree);
|
static void save_function_data (tree);
|
||||||
static void copy_type_enum (tree , 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. */
|
Quotes on semantics can be found in ARM 8.4.3. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
grok_reference_init (tree decl, tree type, tree init, tree *cleanup,
|
grok_reference_init (tree decl, tree type, tree init, int flags)
|
||||||
int flags)
|
|
||||||
{
|
{
|
||||||
tree tmp;
|
|
||||||
|
|
||||||
if (init == NULL_TREE)
|
if (init == NULL_TREE)
|
||||||
{
|
{
|
||||||
if ((DECL_LANG_SPECIFIC (decl) == 0
|
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
|
DECL_INITIAL for local references (instead assigning to them
|
||||||
explicitly); we need to allow the temporary to be initialized
|
explicitly); we need to allow the temporary to be initialized
|
||||||
first. */
|
first. */
|
||||||
tmp = initialize_reference (type, init, decl, cleanup, flags,
|
return initialize_reference (type, init, flags,
|
||||||
tf_warning_or_error);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Designated initializers in arrays are not supported in GNU C++.
|
/* 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. */
|
evaluated dynamically to initialize DECL. */
|
||||||
|
|
||||||
static tree
|
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 type = TREE_TYPE (decl);
|
||||||
tree init_code = NULL;
|
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 (!init && DECL_REALLY_EXTERN (decl))
|
||||||
;
|
;
|
||||||
else if (TREE_CODE (type) == REFERENCE_TYPE)
|
else if (init || type_build_ctor_call (type)
|
||||||
init = grok_reference_init (decl, type, init, cleanup, flags);
|
|| TREE_CODE (type) == REFERENCE_TYPE)
|
||||||
else if (init || type_build_ctor_call (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);
|
check_for_uninitialized_const_var (decl);
|
||||||
/* Do not reshape constructors of vectors (they don't need to be
|
/* Do not reshape constructors of vectors (they don't need to be
|
||||||
reshaped. */
|
reshaped. */
|
||||||
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
else if (BRACE_ENCLOSED_INITIALIZER_P (init))
|
||||||
{
|
{
|
||||||
if (is_std_init_list (type))
|
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))
|
else if (TYPE_NON_AGGREGATE_CLASS (type))
|
||||||
{
|
{
|
||||||
/* Don't reshape if the class has constructors. */
|
/* 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)
|
if (type == error_mark_node)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
if (type_build_ctor_call (type)
|
if ((type_build_ctor_call (type) || CLASS_TYPE_P (type))
|
||||||
|| (CLASS_TYPE_P (type)
|
&& !(flags & LOOKUP_ALREADY_DIGESTED)
|
||||||
&& !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
|
&& !(init && BRACE_ENCLOSED_INITIALIZER_P (init)
|
||||||
|
&& CP_AGGREGATE_TYPE_P (type)))
|
||||||
{
|
{
|
||||||
init_code = build_aggr_init_full_exprs (decl, init, flags);
|
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)
|
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
|
if (pedantic && TREE_CODE (type) == ARRAY_TYPE
|
||||||
&& DECL_INITIAL (decl)
|
&& DECL_INITIAL (decl)
|
||||||
&& TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
|
&& 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 asmspec_tree, int flags)
|
||||||
{
|
{
|
||||||
tree type;
|
tree type;
|
||||||
tree cleanup;
|
VEC(tree,gc) *cleanups = NULL;
|
||||||
const char *asmspec = NULL;
|
const char *asmspec = NULL;
|
||||||
int was_readonly = 0;
|
int was_readonly = 0;
|
||||||
bool var_definition_p = false;
|
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)
|
if (type == error_mark_node)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Assume no cleanup is required. */
|
|
||||||
cleanup = NULL_TREE;
|
|
||||||
|
|
||||||
/* If a name was specified, get the string. */
|
/* If a name was specified, get the string. */
|
||||||
if (at_namespace_scope_p ())
|
if (at_namespace_scope_p ())
|
||||||
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
|
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
|
/* This variable seems to be a non-dependent constant, so process
|
||||||
its initializer. If check_initializer returns non-null the
|
its initializer. If check_initializer returns non-null the
|
||||||
initialization wasn't constant after all. */
|
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)
|
if (init_code == NULL_TREE)
|
||||||
init = 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);
|
error ("Java object %qD not allocated with %<new%>", decl);
|
||||||
init = NULL_TREE;
|
init = NULL_TREE;
|
||||||
}
|
}
|
||||||
init = check_initializer (decl, init, flags, &cleanup);
|
init = check_initializer (decl, init, flags, &cleanups);
|
||||||
/* Thread-local storage cannot be dynamically initialized. */
|
/* Thread-local storage cannot be dynamically initialized. */
|
||||||
if (DECL_THREAD_LOCAL_P (decl) && init)
|
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
|
/* If a CLEANUP_STMT was created to destroy a temporary bound to a
|
||||||
reference, insert it in the statement-tree now. */
|
reference, insert it in the statement-tree now. */
|
||||||
if (cleanup)
|
if (cleanups)
|
||||||
push_cleanup (decl, cleanup, false);
|
{
|
||||||
|
unsigned i; tree t;
|
||||||
|
FOR_EACH_VEC_ELT_REVERSE (tree, cleanups, i, t)
|
||||||
|
push_cleanup (decl, t, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (was_readonly)
|
if (was_readonly)
|
||||||
TREE_READONLY (decl) = 1;
|
TREE_READONLY (decl) = 1;
|
||||||
|
|
|
@ -1877,10 +1877,12 @@ maybe_emit_vtables (tree ctype)
|
||||||
|
|
||||||
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
|
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. */
|
/* It had better be all done at compile-time. */
|
||||||
gcc_assert (!expr);
|
gcc_assert (!expr && !cleanups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write it out. */
|
/* 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
|
if (init && TREE_CODE (exp) == VAR_DECL
|
||||||
&& COMPOUND_LITERAL_P (init))
|
&& COMPOUND_LITERAL_P (init))
|
||||||
{
|
{
|
||||||
|
VEC(tree,gc)* cleanups = NULL;
|
||||||
/* If store_init_value returns NULL_TREE, the INIT has been
|
/* If store_init_value returns NULL_TREE, the INIT has been
|
||||||
recorded as the DECL_INITIAL for EXP. That means there's
|
recorded as the DECL_INITIAL for EXP. That means there's
|
||||||
nothing more we have to do. */
|
nothing more we have to do. */
|
||||||
init = store_init_value (exp, init, flags);
|
init = store_init_value (exp, init, &cleanups, flags);
|
||||||
if (init)
|
if (init)
|
||||||
finish_expr_stmt (init);
|
finish_expr_stmt (init);
|
||||||
|
gcc_assert (!cleanups);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3150,6 +3152,9 @@ build_vec_init (tree base, tree maxindex, tree init,
|
||||||
bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
|
bool try_const = (TREE_CODE (atype) == ARRAY_TYPE
|
||||||
&& (literal_type_p (inner_elt_type)
|
&& (literal_type_p (inner_elt_type)
|
||||||
|| TYPE_HAS_CONSTEXPR_CTOR (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_non_const = false;
|
||||||
bool saw_const = false;
|
bool saw_const = false;
|
||||||
/* If we're initializing a static array, we want to do static
|
/* 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++;
|
num_initialized_elts++;
|
||||||
|
|
||||||
current_stmt_tree ()->stmts_are_full_exprs_p = 1;
|
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);
|
one_init = build_aggr_init (baseref, elt, 0, complain);
|
||||||
else
|
else
|
||||||
one_init = cp_build_modify_expr (baseref, NOP_EXPR,
|
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
|
initialize a static reference. This isn't part of the ABI, but we might
|
||||||
as well call them something readable. */
|
as well call them something readable. */
|
||||||
|
|
||||||
|
static GTY(()) int temp_count;
|
||||||
|
|
||||||
tree
|
tree
|
||||||
mangle_ref_init_variable (const tree variable)
|
mangle_ref_init_variable (const tree variable)
|
||||||
{
|
{
|
||||||
start_mangling (variable);
|
start_mangling (variable);
|
||||||
write_string ("_ZGR");
|
write_string ("_ZGR");
|
||||||
write_name (variable, /*ignore_local_scope=*/0);
|
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);
|
return finish_mangling_get_identifier (/*warn=*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7561,8 +7561,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
|
||||||
|
|
||||||
if (fndecl)
|
if (fndecl)
|
||||||
savew = warningcount, savee = errorcount;
|
savew = warningcount, savee = errorcount;
|
||||||
rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE,
|
rhs = initialize_reference (type, rhs, flags, complain);
|
||||||
/*cleanup=*/NULL, flags, complain);
|
|
||||||
if (fndecl)
|
if (fndecl)
|
||||||
{
|
{
|
||||||
if (warningcount > savew)
|
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. */
|
for static variable. In that case, caller must emit the code. */
|
||||||
|
|
||||||
tree
|
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;
|
tree value, type;
|
||||||
|
|
||||||
|
@ -699,6 +699,8 @@ store_init_value (tree decl, tree init, int flags)
|
||||||
/* Digest the specified initializer into an expression. */
|
/* Digest the specified initializer into an expression. */
|
||||||
value = digest_init_flags (type, init, flags);
|
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++0x constant expression is a semantic, not syntactic, property.
|
||||||
In C++98, make sure that what we thought was a constant expression at
|
In C++98, make sure that what we thought was a constant expression at
|
||||||
template definition time is still constant. */
|
template definition time is still constant. */
|
||||||
|
@ -725,7 +727,16 @@ store_init_value (tree decl, tree init, int flags)
|
||||||
if (value != error_mark_node
|
if (value != error_mark_node
|
||||||
&& (TREE_SIDE_EFFECTS (value)
|
&& (TREE_SIDE_EFFECTS (value)
|
||||||
|| ! initializer_constant_valid_p (value, TREE_TYPE (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
|
/* 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
|
is an automatic variable, the middle end will turn this into a
|
||||||
dynamic initialization later. */
|
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>
|
2011-11-04 Tom de Vries <tom@codesourcery.com>
|
||||||
|
|
||||||
PR tree-optimization/50763
|
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>
|
2011-11-02 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
* Makefile.in (CFILES): Add timeval-utils.c.
|
* 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);
|
return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
|
||||||
|
|
||||||
case 'R':
|
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':
|
case 'A':
|
||||||
return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
|
return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
|
||||||
|
@ -3921,7 +3924,9 @@ d_print_comp (struct d_print_info *dpi, int options,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case DEMANGLE_COMPONENT_REFTEMP:
|
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));
|
d_print_comp (dpi, options, d_left (dc));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue