From 0830ae44cd7f243964cf767561525e0ba194676f Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 7 Aug 2001 13:57:06 +0000 Subject: 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 --- gcc/cp/ChangeLog | 14 +++++++ gcc/cp/call.c | 35 +++++++--------- gcc/cp/class.c | 25 +++--------- gcc/cp/cp-tree.h | 2 +- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/abi/empty4.C | 86 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 125 insertions(+), 41 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/empty4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dbde805..b2d3d3c 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,17 @@ +2001-08-07 Nathan Sidwell + + 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 * tree.c (walk_tree): Walk siblings even if !walk_subtrees. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index bbe6c48..6278095 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 42c03713..a187bc3 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0bc60ae..fd079d2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8578019..c5058bd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2001-08-07 Nathan Sidwell + + * g++.dg/abi/empty4.C: New test. + 2001-08-06 David Billinghurst * g77.f-torture/execute/f90-intrinsic-bit.x: XFAIL on irix6.* and diff --git a/gcc/testsuite/g++.dg/abi/empty4.C b/gcc/testsuite/g++.dg/abi/empty4.C new file mode 100644 index 0000000..39ab9c5 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/empty4.C @@ -0,0 +1,86 @@ +// { dg-do run } + +// Copyright (C) 2001 Free Software Foundation, Inc. +// Contributed by Nathan Sidwell 31 Jul 2001 + +// 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; +} -- cgit v1.1