Avoid clobbering primary virtual base when not in charge.
authorJason Merrill <jason@redhat.com>
Fri, 18 Mar 2016 15:31:29 +0000 (11:31 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 18 Mar 2016 15:31:29 +0000 (11:31 -0400)
* decl.c (build_clobber_this): Factor out of
start_preparsed_function and begin_destructor_body.  Handle
virtual bases better.

From-SVN: r234334

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c

index adecb92f39d383796c09aaf71e2a77f518aa7fb0..0ee9f8b9d439aba472440ad9fef66654118b40ff 100644 (file)
@@ -1,5 +1,9 @@
 2016-03-18  Jason Merrill  <jason@redhat.com>
 
+       * decl.c (build_clobber_this): Factor out of
+       start_preparsed_function and begin_destructor_body.  Handle
+       virtual bases better.
+
        * class.c (build_if_in_charge): Split out from build_base_path.
        * init.c (expand_virtual_init, expand_default_init): Use it.
        * call.c (build_special_member_call): Use it.
index 85d64057c32faf1ee4c17af333c5ad2bace33e63..5cad1413482fd378fe4476b262d7217d6b90766f 100644 (file)
@@ -1988,7 +1988,7 @@ struct GTY(()) lang_type {
 #define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases)
 
 /* The type corresponding to NODE when NODE is used as a base class,
-   i.e., NODE without virtual base classes.  */
+   i.e., NODE without virtual base classes or tail padding.  */
 
 #define CLASSTYPE_AS_BASE(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->as_base)
 
index 0a2e26793e0432cd66102cdc17bc2dd168a16183..f33d2e967b93b5194f30ab19efef754a7c919494 100644 (file)
@@ -13712,6 +13712,43 @@ implicit_default_ctor_p (tree fn)
          && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)));
 }
 
+/* Clobber the contents of *this to let the back end know that the object
+   storage is dead when we enter the constructor or leave the destructor.  */
+
+static tree
+build_clobber_this ()
+{
+  /* Clobbering an empty base is pointless, and harmful if its one byte
+     TYPE_SIZE overlays real data.  */
+  if (is_empty_class (current_class_type))
+    return void_node;
+
+  /* If we have virtual bases, clobber the whole object, but only if we're in
+     charge.  If we don't have virtual bases, clobber the as-base type so we
+     don't mess with tail padding.  */
+  bool vbases = CLASSTYPE_VBASECLASSES (current_class_type);
+
+  tree ctype = current_class_type;
+  if (!vbases)
+    ctype = CLASSTYPE_AS_BASE (ctype);
+
+  tree clobber = build_constructor (ctype, NULL);
+  TREE_THIS_VOLATILE (clobber) = true;
+
+  tree thisref = current_class_ref;
+  if (ctype != current_class_type)
+    {
+      thisref = build_nop (build_reference_type (ctype), current_class_ptr);
+      thisref = convert_from_reference (thisref);
+    }
+
+  tree exprstmt = build2 (MODIFY_EXPR, void_type_node, thisref, clobber);
+  if (vbases)
+    exprstmt = build_if_in_charge (exprstmt);
+
+  return exprstmt;
+}
+
 /* Create the FUNCTION_DECL for a function definition.
    DECLSPECS and DECLARATOR are the parts of the declaration;
    they describe the function's name and the type it returns,
@@ -14127,17 +14164,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
         because part of the initialization might happen before we enter the
         constructor, via AGGR_INIT_ZERO_FIRST (c++/68006).  */
       && !implicit_default_ctor_p (decl1))
-    {
-      /* Insert a clobber to let the back end know that the object storage
-        is dead when we enter the constructor.  */
-      tree btype = CLASSTYPE_AS_BASE (current_class_type);
-      tree clobber = build_constructor (btype, NULL);
-      TREE_THIS_VOLATILE (clobber) = true;
-      tree bref = build_nop (build_reference_type (btype), current_class_ptr);
-      bref = convert_from_reference (bref);
-      tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
-      finish_expr_stmt (exprstmt);
-    }
+    finish_expr_stmt (build_clobber_this ());
 
   if (!processing_template_decl
       && DECL_CONSTRUCTOR_P (decl1)
@@ -14357,18 +14384,7 @@ begin_destructor_body (void)
       if (flag_lifetime_dse
          /* Clobbering an empty base is harmful if it overlays real data.  */
          && !is_empty_class (current_class_type))
-       {
-         /* Insert a cleanup to let the back end know that the object is dead
-            when we exit the destructor, either normally or via exception.  */
-         tree btype = CLASSTYPE_AS_BASE (current_class_type);
-         tree clobber = build_constructor (btype, NULL);
-         TREE_THIS_VOLATILE (clobber) = true;
-         tree bref = build_nop (build_reference_type (btype),
-                                current_class_ptr);
-         bref = convert_from_reference (bref);
-         tree exprstmt = build2 (MODIFY_EXPR, btype, bref, clobber);
-         finish_decl_cleanup (NULL_TREE, exprstmt);
-       }
+       finish_decl_cleanup (NULL_TREE, build_clobber_this ());
 
       /* And insert cleanups for our bases and members so that they
         will be properly destroyed if we throw.  */