From bf08acdaa570ae61e86b92660ddee07d20948919 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 18 Mar 2016 11:31:29 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 4 ++++ gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 62 ++++++++++++++++++++++++++++++------------------ 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index adecb92f39d..0ee9f8b9d43 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2016-03-18 Jason Merrill + * 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 85d64057c32..5cad1413482 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 0a2e26793e0..f33d2e967b9 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. */ -- 2.30.2