call.c (build_over_call): Don't throw away initializations/copies of empty classes...
* call.c (build_over_call): Don't throw away initializations/copies of empty classes; use MODIFY_EXPR and INIT_EXPR as for non-empty classes. * class.c (finish_struct_1): Put the padding byte for an empty class on the TYPE_NONCOPIED_PARTS list for the class. From-SVN: r26970
This commit is contained in:
parent
c15398de77
commit
c1aa4de772
@ -1,3 +1,11 @@
|
||||
1999-05-17 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* call.c (build_over_call): Don't throw away
|
||||
initializations/copies of empty classes; use MODIFY_EXPR and
|
||||
INIT_EXPR as for non-empty classes.
|
||||
* class.c (finish_struct_1): Put the padding byte for an empty
|
||||
class on the TYPE_NONCOPIED_PARTS list for the class.
|
||||
|
||||
1999-05-16 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* decl2.c (build_expr_from_tree): Handle COMPONENT_REFs that
|
||||
|
@ -3426,20 +3426,34 @@ build_over_call (cand, args, flags)
|
||||
else if (! real_lvalue_p (arg)
|
||||
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
|
||||
{
|
||||
tree address;
|
||||
tree to = stabilize_reference
|
||||
(build_indirect_ref (TREE_VALUE (args), 0));
|
||||
|
||||
/* Don't copy the padding byte; it might not have been allocated
|
||||
if to is a base subobject. */
|
||||
if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
|
||||
return build_unary_op
|
||||
(ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to),
|
||||
cp_convert (void_type_node, arg), to),
|
||||
0);
|
||||
|
||||
val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
|
||||
/* If we're initializing an empty class, then we actually
|
||||
have to use a MODIFY_EXPR rather than an INIT_EXPR. The
|
||||
reason is that the dummy padding member in the target may
|
||||
not actually be allocated if TO is a base class
|
||||
subobject. Since we've set TYPE_NONCOPIED_PARTS on the
|
||||
padding, a MODIFY_EXPR will preserve its value, which is
|
||||
the right thing to do if it's not really padding at all.
|
||||
|
||||
It's not safe to just throw away the ARG if we're looking
|
||||
at an empty class because the ARG might contain a
|
||||
TARGET_EXPR which wants to be bound to TO. If it is not,
|
||||
expand_expr will assign a dummy slot for the TARGET_EXPR,
|
||||
and we will call a destructor for it, which is wrong,
|
||||
because we will also destroy TO, but will never have
|
||||
constructed it. */
|
||||
val = build (is_empty_class (DECL_CLASS_CONTEXT (fn))
|
||||
? MODIFY_EXPR : INIT_EXPR,
|
||||
DECL_CONTEXT (fn), to, arg);
|
||||
TREE_SIDE_EFFECTS (val) = 1;
|
||||
return build_unary_op (ADDR_EXPR, val, 0);
|
||||
address = build_unary_op (ADDR_EXPR, val, 0);
|
||||
/* Avoid a warning about this expression, if the address is
|
||||
never used. */
|
||||
TREE_USED (address) = 1;
|
||||
return address;
|
||||
}
|
||||
}
|
||||
else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR]
|
||||
@ -3451,12 +3465,6 @@ build_over_call (cand, args, flags)
|
||||
|
||||
arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0);
|
||||
|
||||
/* Don't copy the padding byte; it might not have been allocated
|
||||
if to is a base subobject. */
|
||||
if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
|
||||
return build (COMPOUND_EXPR, TREE_TYPE (to),
|
||||
cp_convert (void_type_node, arg), to);
|
||||
|
||||
val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
|
||||
TREE_SIDE_EFFECTS (val) = 1;
|
||||
return val;
|
||||
|
@ -3133,6 +3133,7 @@ finish_struct_1 (t, warn_anon)
|
||||
int aggregate = 1;
|
||||
int empty = 1;
|
||||
int has_pointers = 0;
|
||||
tree inline_friends;
|
||||
|
||||
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
|
||||
pedwarn ("anonymous class type not used to declare any objects");
|
||||
@ -3740,6 +3741,13 @@ finish_struct_1 (t, warn_anon)
|
||||
if (DECL_SIZE (x) != integer_zero_node)
|
||||
empty = 0;
|
||||
}
|
||||
|
||||
/* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus,
|
||||
we have to save this before we start modifying
|
||||
TYPE_NONCOPIED_PARTS. */
|
||||
inline_friends = CLASSTYPE_INLINE_FRIENDS (t);
|
||||
CLASSTYPE_INLINE_FRIENDS (t) = NULL_TREE;
|
||||
|
||||
if (empty)
|
||||
{
|
||||
/* C++: do not let empty structures exist. */
|
||||
@ -3747,7 +3755,11 @@ finish_struct_1 (t, warn_anon)
|
||||
(FIELD_DECL, NULL_TREE, char_type_node);
|
||||
TREE_CHAIN (decl) = fields;
|
||||
TYPE_FIELDS (t) = decl;
|
||||
TYPE_NONCOPIED_PARTS (t)
|
||||
= tree_cons (NULL_TREE, decl, TYPE_NONCOPIED_PARTS (t));
|
||||
TREE_STATIC (TYPE_NONCOPIED_PARTS (t)) = 1;
|
||||
}
|
||||
|
||||
if (n_baseclasses)
|
||||
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
|
||||
|
||||
@ -4021,8 +4033,7 @@ finish_struct_1 (t, warn_anon)
|
||||
}
|
||||
|
||||
/* Write out inline function definitions. */
|
||||
do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
|
||||
CLASSTYPE_INLINE_FRIENDS (t) = 0;
|
||||
do_inline_function_hair (t, inline_friends);
|
||||
|
||||
if (CLASSTYPE_VSIZE (t) != 0)
|
||||
{
|
||||
@ -4049,7 +4060,9 @@ finish_struct_1 (t, warn_anon)
|
||||
/* In addition to this one, all the other vfields should be listed. */
|
||||
/* Before that can be done, we have to have FIELD_DECLs for them, and
|
||||
a place to find them. */
|
||||
TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (TYPE_BINFO_VTABLE (t)), vfield);
|
||||
TYPE_NONCOPIED_PARTS (t)
|
||||
= tree_cons (default_conversion (TYPE_BINFO_VTABLE (t)),
|
||||
vfield, TYPE_NONCOPIED_PARTS (t));
|
||||
|
||||
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
|
||||
&& DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
|
||||
|
23
gcc/testsuite/g++.old-deja/g++.other/empty1.C
Normal file
23
gcc/testsuite/g++.old-deja/g++.other/empty1.C
Normal file
@ -0,0 +1,23 @@
|
||||
// Origin: Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
extern "C" void abort();
|
||||
extern "C" void printf(const char*, ...);
|
||||
|
||||
int i;
|
||||
|
||||
struct A;
|
||||
|
||||
struct A* as[10];
|
||||
|
||||
struct A {
|
||||
A () { as[i++] = this; }
|
||||
A (const A&) { as[i++] = this; }
|
||||
~A() { if (i == 0 || as[--i] != this) abort(); }
|
||||
};
|
||||
|
||||
A f() { return A(); }
|
||||
|
||||
int main ()
|
||||
{
|
||||
A a (f ());
|
||||
}
|
Loading…
Reference in New Issue
Block a user