On Thu, 28 Sept 2023 at 10:17, Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > On Wed, Sep 27, 2023 at 12:46:45PM +0200, Jakub Jelinek wrote: > > On Wed, Sep 27, 2023 at 07:17:22AM +0000, Richard Biener wrote: > > > OK I guess. Can you summarize the limitations for non-POD types > > > in the big comment at the start of vec.h? > > > > Still haven't done that, but will do after we flesh out the details > > below. > > > > > (can we put in static_asserts > > > in the places that obviously do not work?) > > > > I've tried to do this though, I think the static_asserts will allow > > making sure we only use what is supportable and will serve better than > > any kind of comment. > > The following patch adds the file comment, as discussed on IRC adds an > exception for qsort/sort/stablesort such that std::pair of 2 trivially > copyable types is also allowed, and fixes some of the grow vs. grow_cleared > issues (on top of the bitmap_head_pod patch far more), but still not all > yet, so I've kept that static_assert for now commented out. Richard > Sandiford said he's playing with poly_int_pod vs. poly_int and I'll resolve > the remaining stuff incrementally afterwards plus enable the assert. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2023-09-28 Jakub Jelinek <ja...@redhat.com> > Jonathan Wakely <jwak...@redhat.com> > > * vec.h: Mention in file comment limited support for non-POD types > in some operations. > (vec_destruct): New function template. > (release): Use it for non-trivially destructible T. > (truncate): Likewise. > (quick_push): Perform a placement new into slot > instead of assignment. > (pop): For non-trivially destructible T return void > rather than T & and destruct the popped element. > (quick_insert, ordered_remove): Note that they aren't suitable > for non-trivially copyable types. Add static_asserts for that. > (block_remove): Assert T is trivially copyable. > (vec_detail::is_trivially_copyable_or_pair): New trait. > (qsort, sort, stablesort): Assert T is trivially copyable or > std::pair with both trivally copyable types. > (quick_grow): Add assert T is trivially default constructible, > for now commented out. > (quick_grow_cleared): Don't call quick_grow, instead inline it > by hand except for the new static_assert. > (gt_ggc_mx): Assert T is trivially destructable. > (auto_vec::operator=): Formatting fixes. > (auto_vec::auto_vec): Likewise. > (vec_safe_grow_cleared): Don't call vec_safe_grow, instead inline > it manually and call quick_grow_cleared method rather than quick_grow. > (safe_grow_cleared): Likewise. > * edit-context.cc (class line_event): Move definition earlier. > * tree-ssa-loop-im.cc (seq_entry::seq_entry): Make default ctor > defaulted. > * ipa-fnsummary.cc (evaluate_properties_for_edge): Use > safe_grow_cleared instead of safe_grow followed by placement new > constructing the elements. > > --- gcc/vec.h.jj 2023-09-27 10:38:50.635845540 +0200 > +++ gcc/vec.h 2023-09-28 11:05:14.776215137 +0200 > @@ -111,6 +111,24 @@ extern void *ggc_realloc (void *, size_t > the 'space' predicate will tell you whether there is spare capacity > in the vector. You will not normally need to use these two functions. > > + Not all vector operations support non-POD types and such restrictions > + are enforced through static assertions. Some operations which often use > + memmove to move elements around like quick_insert, safe_insert, > + ordered_remove, unordered_remove, block_remove etc. require trivially > + copyable types. Sorting operations, qsort, sort and stablesort, require > + those too but as an extension allow also std::pair of 2 trivially copyable > + types which happens to work even when std::pair itself isn't trivially > + copyable. The quick_grow and safe_grow operations require trivially > + default constructible types. One can use quick_grow_cleared or > + safe_grow_cleared for non-trivially default constructible types if needed > + (but of course such operation is more expensive then). The pop operation > + returns reference to the last element only for trivially destructible > + types, for non-trivially destructible types one should use last operation > + followed by pop which in that case returns void. > + And finally, the GC and GC atomic vectors should always be used with > + trivially destructible types, as nothing will invoke destructors when they > + are freed during GC. > + > Notes on the different layout strategies > > * Embeddable vectors (vec<T, A, vl_embed>) > @@ -185,6 +203,16 @@ extern void dump_vec_loc_statistics (voi > /* Hashtable mapping vec addresses to descriptors. */ > extern htab_t vec_mem_usage_hash; > > +/* Destruct N elements in DST. */ > + > +template <typename T> > +inline void > +vec_destruct (T *dst, unsigned n) > +{ > + for ( ; n; ++dst, --n) > + dst->~T (); > +} > + > /* Control data for vectors. This contains the number of allocated > and used slots inside a vector. */ > > @@ -310,6 +338,9 @@ va_heap::release (vec<T, va_heap, vl_emb > if (v == NULL) > return; > > + if (!std::is_trivially_destructible <T>::value)
Do GCC's coding standards really require a space before the template argument list, like for a function parameter list? That style doesn't seem to be used elsewhere (and is not idiomatic for C++ at all). > +namespace vec_detail > +{ > + /* gcc_{qsort,qsort_r,stablesort_r} implementation under the hood > + uses memcpy/memmove to reorder the array elements. > + We want to assert these methods aren't used on types for which > + that isn't appropriate, but unfortunately std::pair of 2 trivially > + copyable types isn't trivially copyable and we use qsort on many > + such std::pair instantiations. Let's allow both trivially > + copyable types and std::pair of 2 trivially copyable types as > + exception for qsort/sort/stablesort. */ > + template<typename T> > + struct is_trivially_copyable_or_pair : std::is_trivially_copyable<T> { }; > + > + template<typename T, typename U> > + struct is_trivially_copyable_or_pair<std::pair<T, U> > The space in "> >" is only required in C++98, we don't need it in C++11. > + : std::integral_constant<bool, std::is_trivially_copyable<T>::value > + && std::is_trivially_copyable<U>::value> { }; > +} > +