On Wed, Mar 4, 2026 at 12:56 PM Jonathan Wakely <[email protected]> wrote:
> As Bug 122300 shows, we have at least one target where the > static_assert added by r16-4422-g1b18a9e53960f3 fails. This patch > resurrects the original proposal for using aligned new that I posted in > https://gcc.gnu.org/pipermail/libstdc++/2025-October/063904.html > > Instead of just asserting that the memory from operator new will be > sufficiently aligned, check whether it will be and use aligned new if > needed. We don't just use aligned new unconditionally, because that can > add overhead on targets where malloc already meets the requirements. > > libstdc++-v3/ChangeLog: > > PR libstdc++/122300 > * src/c++17/fs_path.cc (path::_List::_Impl): Remove > static_asserts. > (path::_List::_Impl::required_alignment) > (path::_List::_Impl::use_aligned_new): New static data members. > (path::_List::_Impl::create_unchecked): Check use_aligned_new > and use aligned new if needed. > (path::_List::_Impl::alloc_size): New static member function. > (path::_List::_Impl_deleter::operator): Check use_aligned_new > and use aligned delete if needed. > --- > > Tested x86_64-linux and bootstrapped pru-unknown-elf, confirming that it > fixes the failed static_assert during bootstrap. > Looks good. Remember discussing these changes with the original patch? we didn't knew if any target was affected. > > libstdc++-v3/src/c++17/fs_path.cc | 27 +++++++++++++++++++++------ > 1 file changed, 21 insertions(+), 6 deletions(-) > > diff --git a/libstdc++-v3/src/c++17/fs_path.cc > b/libstdc++-v3/src/c++17/fs_path.cc > index 9d8d38266789..c217dc278018 100644 > --- a/libstdc++-v3/src/c++17/fs_path.cc > +++ b/libstdc++-v3/src/c++17/fs_path.cc > @@ -260,9 +260,12 @@ struct path::_List::_Impl > > // We use the two least significant bits to store a _Type value so > // require memory aligned to at least 4 bytes: > - static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= 4); > - // Require memory suitably aligned for an _Impl and its value types: > - static_assert(__STDCPP_DEFAULT_NEW_ALIGNMENT__ >= alignof(value_type)); > + static constexpr size_t required_alignment > + = std::max(size_t(4), alignof(value_type)); > + > + // Only use aligned new if needed, because it might be less efficient. > + static constexpr bool use_aligned_new > + = __STDCPP_DEFAULT_NEW_ALIGNMENT__ < required_alignment; > > // Clear the lowest two bits from the pointer (i.e. remove the _Type > value) > static _Impl* notype(_Impl* p) > @@ -297,9 +300,18 @@ struct path::_List::_Impl > static unique_ptr<_Impl, _Impl_deleter> > create_unchecked(int n) > { > - void* p = ::operator new(sizeof(_Impl) + n * sizeof(value_type)); > + const auto bytes = alloc_size(n); > + void* p; > + if constexpr (use_aligned_new) > + p = ::operator new(bytes, align_val_t{required_alignment}); > + else > + p = ::operator new(bytes); > return std::unique_ptr<_Impl, _Impl_deleter>(::new(p) _Impl{n}); > } > + > + // The number of bytes that must be allocated for _Impl with capacity n. > + static size_t > + alloc_size(int n) { return sizeof(_Impl) + n * sizeof(value_type); } > }; > > // Destroy and deallocate an _Impl. > @@ -309,9 +321,12 @@ path::_List::_Impl_deleter::operator()(_Impl* p) > const noexcept > p = _Impl::notype(p); > if (p) > { > - const auto n = p->_M_capacity; > + const auto bytes = _Impl::alloc_size(p->_M_capacity); > p->~_Impl(); > - ::operator delete(p, sizeof(_Impl) + n * sizeof(_Impl::value_type)); > + if constexpr (_Impl::use_aligned_new) > + ::operator delete(p, bytes, > align_val_t{_Impl::required_alignment}); > + else > + ::operator delete(p, bytes); > } > } > > -- > 2.53.0 > >
