On Fri, Mar 11, 2011 at 09:56:59AM -0500, Jason Merrill wrote: > On 03/11/2011 03:01 AM, Jakub Jelinek wrote: > >Do we need to redo parts of class.c anyway? From what I understand, the > >problematic vtbl pointers are at the end of the base types and DECL_SIZE > >is set to the CLASSTYPE_AS_BASE type size, thus those pointers ought to > >be at or beyond the containing field's size. > >So, can't we simply skip subfields whose bit_position is equal or larger > >to containing field's size? Something like (works on the testcase from this > >PR, otherwise untested): > > Sure, that should work. I had been thinking of stopping when we run > out of fields in CLASSTYPE_AS_BASE, but your approach seems simpler.
It worked, here is what I've bootstrapped/regtested on x86_64-linux and i686-linux. Is that ok then? > >Or, in the simplify_aggr_init case where the created tree is handed > >immediately to the gimplifier, there is IMHO no point in initializing > >all fields to zero when the gimplifier throws that immediately away again. > > Unfortunately, pointers to data members make this not good enough: > zero-initializing one means setting the bits to -1. Though I > suppose we could keep track of whether or not a class has a pointer > to data member field somewhere (and therefore need to do this the > hard way) and if not, just use an empty CONSTRUCTOR. Np, we'd need to call a recursive function then to tell us if there is a pointer to data member then. 2011-03-11 Jakub Jelinek <ja...@redhat.com> PR c++/48035 * init.c (build_zero_init_1): Extracted from build_zero_init. Add FIELD_SIZE argument, if non-NULL and field bit_position as not smaller than that, don't add that field's initializer. Pass DECL_SIZE as last argument to build_zero_init_1 for DECL_FIELD_IS_BASE fields. (build_zero_init): Use build_zero_init_1. * g++.dg/inherit/virtual8.C: New test. --- gcc/cp/init.c.jj 2011-03-11 08:06:36.000000000 +0100 +++ gcc/cp/init.c 2011-03-11 08:40:29.321401994 +0100 @@ -140,10 +140,13 @@ initialize_vtbl_ptrs (tree addr) is the number of elements in the array. If STATIC_STORAGE_P is TRUE, initializers are only generated for entities for which zero-initialization does not simply mean filling the storage with - zero bytes. */ + zero bytes. FIELD_SIZE, if non-NULL, is the bit size of the field, + subfields with bit positions at or above that bit size shouldn't + be added. */ -tree -build_zero_init (tree type, tree nelts, bool static_storage_p) +static tree +build_zero_init_1 (tree type, tree nelts, bool static_storage_p, + tree field_size) { tree init = NULL_TREE; @@ -188,15 +191,32 @@ build_zero_init (tree type, tree nelts, if (TREE_CODE (field) != FIELD_DECL) continue; + /* Don't add virtual bases for base classes if they are beyond + the size of the current field, that means it is present + somewhere else in the object. */ + if (field_size) + { + tree bitpos = bit_position (field); + if (TREE_CODE (bitpos) == INTEGER_CST + && !tree_int_cst_lt (bitpos, field_size)) + continue; + } + /* Note that for class types there will be FIELD_DECLs corresponding to base classes as well. Thus, iterating over TYPE_FIELDs will result in correct initialization of all of the subobjects. */ if (!static_storage_p || !zero_init_p (TREE_TYPE (field))) { - tree value = build_zero_init (TREE_TYPE (field), - /*nelts=*/NULL_TREE, - static_storage_p); + tree new_field_size + = (DECL_FIELD_IS_BASE (field) + && DECL_SIZE (field) + && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST) + ? DECL_SIZE (field) : NULL_TREE; + tree value = build_zero_init_1 (TREE_TYPE (field), + /*nelts=*/NULL_TREE, + static_storage_p, + new_field_size); if (value) CONSTRUCTOR_APPEND_ELT(v, field, value); } @@ -244,9 +264,9 @@ build_zero_init (tree type, tree nelts, ce->index = build2 (RANGE_EXPR, sizetype, size_zero_node, max_index); - ce->value = build_zero_init (TREE_TYPE (type), - /*nelts=*/NULL_TREE, - static_storage_p); + ce->value = build_zero_init_1 (TREE_TYPE (type), + /*nelts=*/NULL_TREE, + static_storage_p, NULL_TREE); } /* Build a constructor to contain the initializations. */ @@ -264,6 +284,24 @@ build_zero_init (tree type, tree nelts, return init; } +/* Return an expression for the zero-initialization of an object with + type T. This expression will either be a constant (in the case + that T is a scalar), or a CONSTRUCTOR (in the case that T is an + aggregate), or NULL (in the case that T does not require + initialization). In either case, the value can be used as + DECL_INITIAL for a decl of the indicated TYPE; it is a valid static + initializer. If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS + is the number of elements in the array. If STATIC_STORAGE_P is + TRUE, initializers are only generated for entities for which + zero-initialization does not simply mean filling the storage with + zero bytes. */ + +tree +build_zero_init (tree type, tree nelts, bool static_storage_p) +{ + return build_zero_init_1 (type, nelts, static_storage_p, NULL_TREE); +} + /* Return a suitable initializer for value-initializing an object of type TYPE, as described in [dcl.init]. */ --- gcc/testsuite/g++.dg/inherit/virtual8.C +++ gcc/testsuite/g++.dg/inherit/virtual8.C @@ -0,0 +1,48 @@ +// PR c++/48035 +// { dg-do run } + +#include <new> +#include <cstring> +#include <cstdlib> + +struct A +{ + virtual void foo (void) {} + virtual ~A () {} +}; + +struct B : public A +{ + virtual ~B () {} +}; + +struct C +{ + virtual ~C () {} + int c; +}; + +struct D : public virtual B, public C +{ + virtual ~D () {} +}; + +struct E : public virtual D +{ + virtual ~E () {} +}; + +int +main () +{ + char *v = new char[sizeof (E) + 16]; + memset (v, 0x55, sizeof (E) + 16); + E *e = new (v) E (); + e->~E (); + + for (unsigned i = sizeof (E); i < sizeof (E) + 16; ++i) + if (v[i] != 0x55) + abort (); + + delete[] v; +} Jakub