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:
parent
24a2858412
commit
0830ae44cd
@ -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>
|
2001-08-07 Jason Merrill <jason_merrill@redhat.com>
|
||||||
|
|
||||||
* tree.c (walk_tree): Walk siblings even if !walk_subtrees.
|
* tree.c (walk_tree): Walk siblings even if !walk_subtrees.
|
||||||
|
@ -4259,30 +4259,19 @@ build_over_call (cand, args, flags)
|
|||||||
return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
|
return build_target_expr_with_type (arg, DECL_CONTEXT (fn));
|
||||||
}
|
}
|
||||||
else if (! real_lvalue_p (arg)
|
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 address;
|
||||||
tree to = stabilize_reference
|
tree to = stabilize_reference
|
||||||
(build_indirect_ref (TREE_VALUE (args), 0));
|
(build_indirect_ref (TREE_VALUE (args), 0));
|
||||||
|
|
||||||
/* If we're initializing an empty class, then we actually
|
val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
|
||||||
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);
|
|
||||||
address = 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
|
/* Avoid a warning about this expression, if the address is
|
||||||
never used. */
|
never used. */
|
||||||
@ -4298,8 +4287,14 @@ build_over_call (cand, args, flags)
|
|||||||
(build_indirect_ref (TREE_VALUE (converted_args), 0));
|
(build_indirect_ref (TREE_VALUE (converted_args), 0));
|
||||||
|
|
||||||
arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (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;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4386,7 +4386,7 @@ check_bases_and_members (t, empty_p)
|
|||||||
|| TYPE_HAS_ASSIGN_REF (t));
|
|| TYPE_HAS_ASSIGN_REF (t));
|
||||||
TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
|
TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
|
||||||
TYPE_HAS_COMPLEX_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
|
/* Synthesize any needed methods. Note that methods will be synthesized
|
||||||
for anonymous unions; grok_x_components undoes that. */
|
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_NEARLY_EMPTY_P (t) = 0;
|
||||||
|
|
||||||
/* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus,
|
/* CLASSTYPE_INLINE_FRIENDS is really TYPE_NONCOPIED_PARTS. Thus,
|
||||||
we have to save this before we start modifying
|
we have to save this before we zap TYPE_NONCOPIED_PARTS. */
|
||||||
TYPE_NONCOPIED_PARTS. */
|
|
||||||
fixup_inline_methods (t);
|
fixup_inline_methods (t);
|
||||||
|
|
||||||
/* Layout the non-static data members. */
|
/* 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);
|
padding = build_decl (FIELD_DECL, NULL_TREE, char_type_node);
|
||||||
place_field (rli, padding);
|
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
|
/* 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 the VTT for T. */
|
||||||
build_vtt (t);
|
build_vtt (t);
|
||||||
|
|
||||||
if (TYPE_VFIELD (t))
|
if (warn_nonvdtor && TYPE_POLYMORPHIC_P (t) && TYPE_HAS_DESTRUCTOR (t)
|
||||||
{
|
&& DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 1)) == NULL_TREE)
|
||||||
/* In addition to this one, all the other vfields should be listed. */
|
cp_warning ("`%#T' has virtual functions but non-virtual destructor", t);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
hack_incomplete_structures (t);
|
hack_incomplete_structures (t);
|
||||||
|
|
||||||
|
@ -2469,7 +2469,7 @@ extern int flag_new_for_scope;
|
|||||||
#define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) \
|
#define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) \
|
||||||
(TYPE_LANG_FLAG_4(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. */
|
a bitwise copy. */
|
||||||
#define TYPE_HAS_TRIVIAL_INIT_REF(NODE) \
|
#define TYPE_HAS_TRIVIAL_INIT_REF(NODE) \
|
||||||
(TYPE_HAS_INIT_REF (NODE) && ! TYPE_HAS_COMPLEX_INIT_REF (NODE))
|
(TYPE_HAS_INIT_REF (NODE) && ! TYPE_HAS_COMPLEX_INIT_REF (NODE))
|
||||||
|
@ -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>
|
2001-08-06 David Billinghurst <David.Billinghurst@riotinto.com>
|
||||||
|
|
||||||
* g77.f-torture/execute/f90-intrinsic-bit.x: XFAIL on irix6.* and
|
* g77.f-torture/execute/f90-intrinsic-bit.x: XFAIL on irix6.* and
|
||||||
|
86
gcc/testsuite/g++.dg/abi/empty4.C
Normal file
86
gcc/testsuite/g++.dg/abi/empty4.C
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user