re PR c++/3820 (GCC 3.0 crashes with empty base class)
authorNathan Sidwell <nathan@codesourcery.com>
Tue, 7 Aug 2001 13:57:06 +0000 (13:57 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 7 Aug 2001 13:57:06 +0000 (13:57 +0000)
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
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/empty4.C [new file with mode: 0644]

index dbde805..b2d3d3c 100644 (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.
index bbe6c48..6278095 100644 (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;
     }
 
index 42c0371..a187bc3 100644 (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);
 
index 0bc60ae..fd079d2 100644 (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))
index 8578019..c5058bd 100644 (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
diff --git a/gcc/testsuite/g++.dg/abi/empty4.C b/gcc/testsuite/g++.dg/abi/empty4.C
new file mode 100644 (file)
index 0000000..39ab9c5
--- /dev/null
@@ -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;
+}