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>
|
1999-05-16 Mark Mitchell <mark@codesourcery.com>
|
||||||
|
|
||||||
* decl2.c (build_expr_from_tree): Handle COMPONENT_REFs that
|
* 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)
|
else if (! real_lvalue_p (arg)
|
||||||
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
|
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
|
||||||
{
|
{
|
||||||
|
tree address;
|
||||||
tree to = stabilize_reference
|
tree to = stabilize_reference
|
||||||
(build_indirect_ref (TREE_VALUE (args), 0));
|
(build_indirect_ref (TREE_VALUE (args), 0));
|
||||||
|
|
||||||
/* Don't copy the padding byte; it might not have been allocated
|
/* If we're initializing an empty class, then we actually
|
||||||
if to is a base subobject. */
|
have to use a MODIFY_EXPR rather than an INIT_EXPR. The
|
||||||
if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
|
reason is that the dummy padding member in the target may
|
||||||
return build_unary_op
|
not actually be allocated if TO is a base class
|
||||||
(ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to),
|
subobject. Since we've set TYPE_NONCOPIED_PARTS on the
|
||||||
cp_convert (void_type_node, arg), to),
|
padding, a MODIFY_EXPR will preserve its value, which is
|
||||||
0);
|
the right thing to do if it's not really padding at all.
|
||||||
|
|
||||||
val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
|
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;
|
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]
|
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);
|
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);
|
val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
|
||||||
TREE_SIDE_EFFECTS (val) = 1;
|
TREE_SIDE_EFFECTS (val) = 1;
|
||||||
return val;
|
return val;
|
||||||
|
@ -3133,6 +3133,7 @@ finish_struct_1 (t, warn_anon)
|
|||||||
int aggregate = 1;
|
int aggregate = 1;
|
||||||
int empty = 1;
|
int empty = 1;
|
||||||
int has_pointers = 0;
|
int has_pointers = 0;
|
||||||
|
tree inline_friends;
|
||||||
|
|
||||||
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
|
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
|
||||||
pedwarn ("anonymous class type not used to declare any objects");
|
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)
|
if (DECL_SIZE (x) != integer_zero_node)
|
||||||
empty = 0;
|
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)
|
if (empty)
|
||||||
{
|
{
|
||||||
/* C++: do not let empty structures exist. */
|
/* C++: do not let empty structures exist. */
|
||||||
@ -3747,7 +3755,11 @@ finish_struct_1 (t, warn_anon)
|
|||||||
(FIELD_DECL, NULL_TREE, char_type_node);
|
(FIELD_DECL, NULL_TREE, char_type_node);
|
||||||
TREE_CHAIN (decl) = fields;
|
TREE_CHAIN (decl) = fields;
|
||||||
TYPE_FIELDS (t) = decl;
|
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)
|
if (n_baseclasses)
|
||||||
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
|
TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
|
||||||
|
|
||||||
@ -4021,8 +4033,7 @@ finish_struct_1 (t, warn_anon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write out inline function definitions. */
|
/* Write out inline function definitions. */
|
||||||
do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
|
do_inline_function_hair (t, inline_friends);
|
||||||
CLASSTYPE_INLINE_FRIENDS (t) = 0;
|
|
||||||
|
|
||||||
if (CLASSTYPE_VSIZE (t) != 0)
|
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. */
|
/* 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
|
/* Before that can be done, we have to have FIELD_DECLs for them, and
|
||||||
a place to find them. */
|
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)
|
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
|
||||||
&& DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
|
&& 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