call.c (build_over_call): Don't throw away initializations/copies of empty classes...
authorMark Mitchell <mark@codesourcery.com>
Mon, 17 May 1999 07:42:26 +0000 (07:42 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Mon, 17 May 1999 07:42:26 +0000 (07:42 +0000)
* 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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/testsuite/g++.old-deja/g++.other/empty1.C [new file with mode: 0644]

index 51479528fd9cb7bb430c60f944ab8dbd1ef06b19..a43deddfdb1726f53da1459a4f3fabce626e7130 100644 (file)
@@ -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>
 
        * decl2.c (build_expr_from_tree): Handle COMPONENT_REFs that
index 1dccabcf10201eaa7ab45e29c854cd3776944eb7..496cf91e17efc233d3cf9ccb05e730a1e2fbc27e 100644 (file)
@@ -3426,20 +3426,34 @@ build_over_call (cand, args, flags)
       else if (! real_lvalue_p (arg)
               || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
        {
+         tree address;
          tree to = stabilize_reference
            (build_indirect_ref (TREE_VALUE (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_unary_op
-             (ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to),
-                                cp_convert (void_type_node, arg), to),
-              0);
-
-         val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+         /* 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_CLASS_CONTEXT (fn))
+                      ? MODIFY_EXPR : INIT_EXPR, 
+                      DECL_CONTEXT (fn), to, arg);
          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]
@@ -3451,12 +3465,6 @@ build_over_call (cand, args, flags)
 
       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);
       TREE_SIDE_EFFECTS (val) = 1;
       return val;
index 1466e94977172d6d98c896f4a101310b78460e22..f7998c1c9769c188ae0dc8abb2b9fa967e85d0da 100644 (file)
@@ -3133,6 +3133,7 @@ finish_struct_1 (t, warn_anon)
   int aggregate = 1;
   int empty = 1;
   int has_pointers = 0;
+  tree inline_friends;
 
   if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
     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)
          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)
     {
       /* C++: do not let empty structures exist.  */
@@ -3747,7 +3755,11 @@ finish_struct_1 (t, warn_anon)
        (FIELD_DECL, NULL_TREE, char_type_node);
       TREE_CHAIN (decl) = fields;
       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)
     TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
 
@@ -4021,8 +4033,7 @@ finish_struct_1 (t, warn_anon)
     }
 
   /* Write out inline function definitions.  */
-  do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
-  CLASSTYPE_INLINE_FRIENDS (t) = 0;
+  do_inline_function_hair (t, inline_friends);
 
   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.  */
       /* Before that can be done, we have to have FIELD_DECLs for them, and
         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)
          && DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
diff --git a/gcc/testsuite/g++.old-deja/g++.other/empty1.C b/gcc/testsuite/g++.old-deja/g++.other/empty1.C
new file mode 100644 (file)
index 0000000..0789884
--- /dev/null
@@ -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 ());
+}