re PR c++/3820 (GCC 3.0 crashes with empty base class)

cp:
	PR c++/3820
	Stop using TYPE_NONCOPIED_PARTS.
	* call.c (build_over_call): Be careful when copy constructing
	or assigning to an empty class.
	* class.c (check_bases_and_members): It has a
	COMPLEX_ASSIGN_REF if it has a vptr.
	(layout_class_type): Don't add empty class padding to
	TYPE_NONCOPIED_PARTS.
	(finish_struct_1): Don't add the VFIELD either.
	* cp-tree.h (TYPE_HAS_TRIVIAL_INIT_REF): Mention _copy_
	initialization.
testsuite:
	* g++.dg/abi/empty4.C: New test.

From-SVN: r44691
This commit is contained in:
Nathan Sidwell 2001-08-07 13:57:06 +00:00 committed by Nathan Sidwell
parent 24a2858412
commit 0830ae44cd
6 changed files with 125 additions and 41 deletions

View File

@ -1,3 +1,17 @@
2001-08-07 Nathan Sidwell <nathan@codesourcery.com>
PR c++/3820
Stop using TYPE_NONCOPIED_PARTS.
* call.c (build_over_call): Be careful when copy constructing
or assigning to an empty class.
* class.c (check_bases_and_members): It has a
COMPLEX_ASSIGN_REF if it has a vptr.
(layout_class_type): Don't add empty class padding to
TYPE_NONCOPIED_PARTS.
(finish_struct_1): Don't add the VFIELD either.
* cp-tree.h (TYPE_HAS_TRIVIAL_INIT_REF): Mention _copy_
initialization.
2001-08-07 Jason Merrill <jason_merrill@redhat.com>
* tree.c (walk_tree): Walk siblings even if !walk_subtrees.

View File

@ -4259,30 +4259,19 @@ build_over_call (cand, args, flags)
return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
}
else if (! real_lvalue_p (arg)
|| TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
/* Empty classes have padding which can be hidden
inside an (empty) base of the class. This must not
be touched as it might overlay things. When the
gcc core learns about empty classes, we can treat it
like other classes. */
|| (!is_empty_class (DECL_CONTEXT (fn))
&& TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))))
{
tree address;
tree to = stabilize_reference
(build_indirect_ref (TREE_VALUE (args), 0));
/* 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_CONTEXT (fn))
? MODIFY_EXPR : INIT_EXPR,
DECL_CONTEXT (fn), to, arg);
val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
address = build_unary_op (ADDR_EXPR, val, 0);
/* Avoid a warning about this expression, if the address is
never used. */
@ -4298,8 +4287,14 @@ build_over_call (cand, args, flags)
(build_indirect_ref (TREE_VALUE (converted_args), 0));
arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0);
if (is_empty_class (TREE_TYPE (to)))
{
TREE_USED (arg) = 1;
val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
val = build (COMPOUND_EXPR, DECL_CONTEXT (fn), arg, to);
}
else
val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
return val;
}

View File

@ -4386,7 +4386,7 @@ check_bases_and_members (t, empty_p)
|| TYPE_HAS_ASSIGN_REF (t));
TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t);
/* Synthesize any needed methods. Note that methods will be synthesized
for anonymous unions; grok_x_components undoes that. */
@ -4877,8 +4877,7 @@ layout_class_type (t, empty_p, vfuns_p,
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
/* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus,
we have to save this before we start modifying
TYPE_NONCOPIED_PARTS. */
we have to save this before we zap TYPE_NONCOPIED_PARTS. */
fixup_inline_methods (t);
/* Layout the non-static data members. */
@ -4974,9 +4973,6 @@ layout_class_type (t, empty_p, vfuns_p,
padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
place_field (rli, padding);
TYPE_NONCOPIED_PARTS (t)
= tree_cons (NULL_TREE, padding, TYPE_NONCOPIED_PARTS (t));
TREE_STATIC (TYPE_NONCOPIED_PARTS (t)) = 1;
}
/* Let the back-end lay out the type. Note that at this point we
@ -5233,20 +5229,9 @@ finish_struct_1 (t)
/* Build the VTT for T. */
build_vtt (t);
if (TYPE_VFIELD (t))
{
/* 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)
= tree_cons (default_conversion (TYPE_BINFO_VTABLE (t)),
TYPE_VFIELD (t), TYPE_NONCOPIED_PARTS (t));
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 1)) == NULL_TREE)
cp_warning ("`%#T' has virtual functions but non-virtual destructor",
t);
}
if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t) && TYPE_HAS_DESTRUCTOR (t)
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 1)) == NULL_TREE)
cp_warning ("`%#T' has virtual functions but non-virtual destructor", t);
hack_incomplete_structures (t);

View File

@ -2469,7 +2469,7 @@ extern int flag_new_for_scope;
#define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) \
(TYPE_LANG_FLAG_4(NODE))
/* Nonzero for class type means that initialization of this type can use
/* Nonzero for class type means that copy initialization of this type can use
a bitwise copy. */
#define TYPE_HAS_TRIVIAL_INIT_REF(NODE) \
(TYPE_HAS_INIT_REF (NODE) && ! TYPE_HAS_COMPLEX_INIT_REF (NODE))

View File

@ -1,3 +1,7 @@
2001-08-07 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/abi/empty4.C: New test.
2001-08-06 David Billinghurst <David.Billinghurst@riotinto.com>
* g77.f-torture/execute/f90-intrinsic-bit.x: XFAIL on irix6.* and

View File

@ -0,0 +1,86 @@
// { dg-do run }
// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 31 Jul 2001 <nathan@codesourcery.com>
// Bug 3820. We were bit copying empty bases including the
// padding. Which clobbers whatever they overlay.
struct Empty {};
struct Inter : Empty {};
int now = 0;
struct NonPod
{
int m;
NonPod () {m = 0x12345678;}
NonPod (int m_) {m = m_;}
NonPod &operator= (NonPod const &src) {now = m; m = src.m;}
NonPod (NonPod const &src) {m = src.m;}
};
struct A : Inter
{
A (int c) {m = c;}
NonPod m;
};
struct B
{
Inter empty;
NonPod m;
B (int c) {m = c;}
};
struct C : NonPod, Inter
{
C (int c) : NonPod (c), Inter () {}
};
int main ()
{
A a (0x12131415);
int was = a.m.m;
a = 0x22232425;
if (was != now)
return 1; // we copied the empty base which clobbered a.m.m's
// original value.
A b (0x32333435);
*(Inter *)&a = *(Inter *)&b;
if (a.m.m != 0x22232425)
return 2; // we copied padding, which clobbered a.m.m
A b2 (0x32333435);
(Inter &)b2 = Inter ();
if (b2.m.m != 0x32333435)
return 2; // we copied padding, which clobbered b2.m.m
B c (0x12131415);
was = c.m.m;
c = 0x22232425;
if (was != now)
return 3;
B d (0x32333435);
c.empty = d.empty;
if (c.m.m != 0x22232425)
return 4;
C e (0x32333435);
if (e.m != 0x32333435)
return 2; // we copied padding
return 0;
}