On Fri, Feb 16, 2018 at 02:14:09PM -0700, Martin Sebor wrote: > On 02/16/2018 01:44 PM, Jakub Jelinek wrote: > > On Fri, Feb 16, 2018 at 09:25:30PM +0100, Richard Biener wrote: > > > But the broken compilers will overwrite the memset data with possibly > > > uninitialized fields of a TARGET_EXPR. > > > > Perhaps for hash-table.h we could use: > > #ifndef BROKEN_VALUE_INITIALIZATION > > for ( ; size; ++entries, --size) > > *entries = value_type (); > > #else > > union U { char c[sizeof (value_type)]; value_type v; } u; > > In C++ 98 a type with a constructor cannot be a member of a union > so the above wouldn't be valid but if I understand what you're > trying to do you don't need the member. All you need is a buffer. > Something like this? > > char __attribute__ ((aligned (__alignof__ (value_type)))) > buf [sizeof (value_type)] = "";
Note, this doesn't work, as G++ <= 4.2 rejects: template <typename value_type> struct S { char __attribute__ ((__aligned__ (__alignof__ (value_type)))) buf[sizeof (value_type)]; }; S<int> s; with: error: requested alignment is not a constant The following works though, and has been successfully bootstrapped/regtested on x86_64-linux and i686-linux. It will fail if we use hash_table on overaligned value_type type with alignment > 64, but that is not completely unlikely on any target I'm aware of. It uses __alignof__ which should be supported by the system GCC's we support for which BROKEN_VALUE_INITIALIZATION is true (i.e. >= 3.4 and <= 4.3), non-GCC compilers shouldn't get here due to GCC_VERSION != 0 unless they pretend to be GCC compatible. Bootstrapped with system gcc34/g++34 on x86_64-linux, ok for trunk? 2018-02-17 Jakub Jelinek <ja...@redhat.com> PR bootstrap/84405 * vec.h (vec_default_construct): For BROKEN_VALUE_INITIALIZATION use memset and value initialization afterwards. * hash-table.h (hash_table<Descriptor, Allocator>::empty_slow): For BROKEN_VALUE_INITIALIZATION use placement new into a previously cleared appropriately aligned buffer. --- gcc/vec.h.jj 2018-02-16 19:39:03.637058918 +0100 +++ gcc/vec.h 2018-02-16 23:51:55.389582056 +0100 @@ -490,12 +490,11 @@ template <typename T> inline void vec_default_construct (T *dst, unsigned n) { -#ifndef BROKEN_VALUE_INITIALIZATION - for ( ; n; ++dst, --n) - ::new (static_cast<void*>(dst)) T (); -#else +#ifdef BROKEN_VALUE_INITIALIZATION memset (dst, '\0', sizeof (T) * n); #endif + for ( ; n; ++dst, --n) + ::new (static_cast<void*>(dst)) T (); } /* Copy-construct N elements in DST from *SRC. */ --- gcc/hash-table.h.jj 2018-02-16 19:39:03.660058934 +0100 +++ gcc/hash-table.h 2018-02-17 00:01:24.207723925 +0100 @@ -808,7 +808,18 @@ hash_table<Descriptor, Allocator>::empty for ( ; size; ++entries, --size) *entries = value_type (); #else - memset (entries, 0, size * sizeof (value_type)); + /* To workaround older GCC versions which don't handle value + initialization right, use a placement new into previously + cleared buffer. */ + char buf[2 * sizeof (value_type) + 64]; + gcc_assert (__alignof__ (value_type) <= sizeof (value_type) + 64); + char *q = (buf + sizeof (value_type) + 64 + - ((uintptr_t) buf % __alignof__ (value_type))); + memset (q, '\0', sizeof (value_type)); + value_type *p = ::new (q) value_type (); + for ( ; size; ++entries, --size) + *entries = *p; + p->~value_type (); #endif } m_n_deleted = 0; Jakub