Commit bf08acda by Jason Merrill Committed by Jason Merrill

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
parent eb0dbdc7
2016-03-18 Jason Merrill <jason@redhat.com> 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. * class.c (build_if_in_charge): Split out from build_base_path.
* init.c (expand_virtual_init, expand_default_init): Use it. * init.c (expand_virtual_init, expand_default_init): Use it.
* call.c (build_special_member_call): Use it. * call.c (build_special_member_call): Use it.
......
...@@ -1988,7 +1988,7 @@ struct GTY(()) lang_type { ...@@ -1988,7 +1988,7 @@ struct GTY(()) lang_type {
#define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases) #define CLASSTYPE_VBASECLASSES(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->vbases)
/* The type corresponding to NODE when NODE is used as a base class, /* 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) #define CLASSTYPE_AS_BASE(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->as_base)
......
...@@ -13712,6 +13712,43 @@ implicit_default_ctor_p (tree fn) ...@@ -13712,6 +13712,43 @@ implicit_default_ctor_p (tree fn)
&& sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (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. /* Create the FUNCTION_DECL for a function definition.
DECLSPECS and DECLARATOR are the parts of the declaration; DECLSPECS and DECLARATOR are the parts of the declaration;
they describe the function's name and the type it returns, they describe the function's name and the type it returns,
...@@ -14127,17 +14164,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) ...@@ -14127,17 +14164,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
because part of the initialization might happen before we enter the because part of the initialization might happen before we enter the
constructor, via AGGR_INIT_ZERO_FIRST (c++/68006). */ constructor, via AGGR_INIT_ZERO_FIRST (c++/68006). */
&& !implicit_default_ctor_p (decl1)) && !implicit_default_ctor_p (decl1))
{ finish_expr_stmt (build_clobber_this ());
/* 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);
}
if (!processing_template_decl if (!processing_template_decl
&& DECL_CONSTRUCTOR_P (decl1) && DECL_CONSTRUCTOR_P (decl1)
...@@ -14357,18 +14384,7 @@ begin_destructor_body (void) ...@@ -14357,18 +14384,7 @@ begin_destructor_body (void)
if (flag_lifetime_dse if (flag_lifetime_dse
/* Clobbering an empty base is harmful if it overlays real data. */ /* Clobbering an empty base is harmful if it overlays real data. */
&& !is_empty_class (current_class_type)) && !is_empty_class (current_class_type))
{ finish_decl_cleanup (NULL_TREE, build_clobber_this ());
/* 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);
}
/* And insert cleanups for our bases and members so that they /* And insert cleanups for our bases and members so that they
will be properly destroyed if we throw. */ will be properly destroyed if we throw. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment