https://gcc.gnu.org/g:ac8c61b62e71ffdcaebfd4cfc03f58fe542855dd
commit r15-1713-gac8c61b62e71ffdcaebfd4cfc03f58fe542855dd Author: Jonathan Wakely <jwak...@redhat.com> Date: Wed Jun 26 12:40:51 2024 +0100 libstdc++: Simplify <ext/aligned_buffer.h> class templates As noted in a comment, the __gnu_cxx::__aligned_membuf class template can be simplified, because alignof(T) and alignas(T) use the correct alignment for a data member. That's true since GCC 8 and Clang 8. The EDG front end (as used by Intel icc, aka "Intel C++ Compiler Classic") does not implement the PR c++/69560 change, so keep using the old implementation when __EDG__ is defined, to avoid an ABI change for icc. For __gnu_cxx::__aligned_buffer<T> all supported compilers agree on the value of __alignof__(T), but we can still simplify it by removing the dependency on std::aligned_storage<sizeof(T), __alignof__(T)>. Add a test that checks that the aligned buffer types have the expected alignment, so that we can tell if changes like this affect their ABI properties. libstdc++-v3/ChangeLog: * include/ext/aligned_buffer.h (__aligned_membuf): Use alignas(T) directly instead of defining a struct and using 9its alignment. (__aligned_buffer): Remove use of std::aligned_storage. * testsuite/abi/aligned_buffers.cc: New test. Diff: --- libstdc++-v3/include/ext/aligned_buffer.h | 20 ++++++------- libstdc++-v3/testsuite/abi/aligned_buffers.cc | 42 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/libstdc++-v3/include/ext/aligned_buffer.h b/libstdc++-v3/include/ext/aligned_buffer.h index 26b36609fa5..9c2c628e54a 100644 --- a/libstdc++-v3/include/ext/aligned_buffer.h +++ b/libstdc++-v3/include/ext/aligned_buffer.h @@ -49,11 +49,15 @@ namespace __gnu_cxx // Target macro ADJUST_FIELD_ALIGN can produce different alignment for // types when used as class members. __aligned_membuf is intended // for use as a class member, so align the buffer as for a class member. - // Since GCC 8 we could just use alignof(_Tp) instead, but older - // versions of non-GNU compilers might still need this trick. + // Since GCC 8 we can just use alignas(_Tp) to get the right alignment. +#ifdef __EDG__ + // The EDG front end does not implement the PR c++/69560 alignof change. struct _Tp2 { _Tp _M_t; }; - - alignas(__alignof__(_Tp2::_M_t)) unsigned char _M_storage[sizeof(_Tp)]; + alignas(__alignof__(_Tp2::_M_t)) +#else + alignas(_Tp) +#endif + unsigned char _M_storage[sizeof(_Tp)]; __aligned_membuf() = default; @@ -81,8 +85,6 @@ namespace __gnu_cxx template<typename _Tp> using __aligned_buffer = __aligned_membuf<_Tp>; #else -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // Similar to __aligned_membuf but aligned for complete objects, not members. // This type is used in <forward_list>, <future>, <bits/shared_ptr_base.h> // and <bits/hashtable_policy.h>, but ideally they would use __aligned_membuf @@ -90,10 +92,9 @@ namespace __gnu_cxx // This type is still used to avoid an ABI change. template<typename _Tp> struct __aligned_buffer - : std::aligned_storage<sizeof(_Tp), __alignof__(_Tp)> { - typename - std::aligned_storage<sizeof(_Tp), __alignof__(_Tp)>::type _M_storage; + // Using __alignof__ gives the alignment for a complete object. + alignas(__alignof__(_Tp)) unsigned char _M_storage[sizeof(_Tp)]; __aligned_buffer() = default; @@ -120,7 +121,6 @@ namespace __gnu_cxx _M_ptr() const noexcept { return static_cast<const _Tp*>(_M_addr()); } }; -#pragma GCC diagnostic pop #endif } // namespace diff --git a/libstdc++-v3/testsuite/abi/aligned_buffers.cc b/libstdc++-v3/testsuite/abi/aligned_buffers.cc new file mode 100644 index 00000000000..b4b8ea13970 --- /dev/null +++ b/libstdc++-v3/testsuite/abi/aligned_buffers.cc @@ -0,0 +1,42 @@ +// { dg-do compile { target c++11 } } + +// Check alignment of the buffer types used for uninitialized storage. + +#include <ext/aligned_buffer.h> + +template<typename T> using membuf = __gnu_cxx::__aligned_membuf<T>; +template<typename T> using objbuf = __gnu_cxx::__aligned_buffer<T>; + +template<typename T> +constexpr bool +check_alignof_membuf() +{ + return alignof(membuf<T>) == alignof(T) + && __alignof__(membuf<T>) == alignof(T); +} + +template<typename T> +constexpr bool +check_alignof_objbuf() +{ +#if _GLIBCXX_INLINE_VERSION + // For the gnu-versioned-namespace ABI __aligned_buffer == __aligned_membuf. + return check_alignof_membuf<T>(); +#else + return alignof(objbuf<T>) == __alignof__(T) + && __alignof__(objbuf<T>) == __alignof__(T); +#endif +} + +struct S { long long l; }; +struct alignas(128) X { char x; }; +static_assert( check_alignof_membuf<int>(), "membuf<int>" ); +static_assert( check_alignof_membuf<long long>(), "membuf<long long>" ); +static_assert( check_alignof_membuf<void*>(), "membuf<void*>" ); +static_assert( check_alignof_membuf<S>(), "membuf<S>" ); +static_assert( check_alignof_membuf<X>(), "membuf<X>" ); +static_assert( check_alignof_objbuf<int>(), "objbuf<int>" ); +static_assert( check_alignof_objbuf<long long>(), "objbuf<long long>" ); +static_assert( check_alignof_objbuf<void*>(), "objbuf<void*>" ); +static_assert( check_alignof_objbuf<S>(), "objbuf<S>" ); +static_assert( check_alignof_objbuf<X>(), "objbuf<X>" );