aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2016-03-18 11:31:29 -0400
committerJason Merrill <jason@gcc.gnu.org>2016-03-18 11:31:29 -0400
commitbf08acdaa570ae61e86b92660ddee07d20948919 (patch)
treee7b210541a6caae5eee27054c7b5450e977bda2a
parenteb0dbdc723bee41672dbbfe2c734a65f44fc28c0 (diff)
downloadgcc-bf08acdaa570ae61e86b92660ddee07d20948919.zip
gcc-bf08acdaa570ae61e86b92660ddee07d20948919.tar.gz
gcc-bf08acdaa570ae61e86b92660ddee07d20948919.tar.bz2
Avoid clobbering primary virtual base when not in charge.
* decl.c (build_clobber_this): Factor out of start_preparsed_function and begin_destructor_body. Handle virtual bases better. From-SVN: r234334
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c62
3 files changed, 44 insertions, 24 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index adecb92..0ee9f8b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 85d6405..5cad141 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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)
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0a2e267..f33d2e9 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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. */