diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-06-26 12:40:51 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2024-06-28 20:19:02 +0100 |
commit | ac8c61b62e71ffdcaebfd4cfc03f58fe542855dd (patch) | |
tree | a588d6c333a586362dc54b216c540dfb1246b909 | |
parent | 5612541834c063dd4126fb059e59c5dc8d5f2f8e (diff) | |
download | gcc-ac8c61b62e71ffdcaebfd4cfc03f58fe542855dd.zip gcc-ac8c61b62e71ffdcaebfd4cfc03f58fe542855dd.tar.gz gcc-ac8c61b62e71ffdcaebfd4cfc03f58fe542855dd.tar.bz2 |
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.
-rw-r--r-- | libstdc++-v3/include/ext/aligned_buffer.h | 20 | ||||
-rw-r--r-- | 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 26b3660..9c2c628 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 0000000..b4b8ea1 --- /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>" ); |