From 08c65bca8818b0a9f713a3a354c5083914b985bc Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Sat, 31 Aug 2024 09:39:03 +0200 Subject: [PATCH] [libc++] Fix __datasizeof_v for Clang17 and 18 in C++03 --- libcxx/include/__config | 14 +------------ libcxx/include/__type_traits/datasizeof.h | 20 ++++--------------- .../type_traits/datasizeof.compile.pass.cpp | 20 ++++++++++++++++++- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index b8ec905a5cbfa6..bccf90d1dbacd2 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -997,21 +997,9 @@ typedef __char32_t char32_t; // (If/when MSVC breaks its C++ ABI, it will be changed to work as intended.) // However, MSVC implements [[msvc::no_unique_address]] which does what // [[no_unique_address]] is supposed to do, in general. - -// Clang-cl does not yet (14.0) implement either [[no_unique_address]] or -// [[msvc::no_unique_address]] though. If/when it does implement -// [[msvc::no_unique_address]], this should be preferred though. # define _LIBCPP_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] -# elif __has_cpp_attribute(no_unique_address) -# define _LIBCPP_NO_UNIQUE_ADDRESS [[__no_unique_address__]] # else -# define _LIBCPP_NO_UNIQUE_ADDRESS /* nothing */ -// Note that this can be replaced by #error as soon as clang-cl -// implements msvc::no_unique_address, since there should be no C++20 -// compiler that doesn't support one of the two attributes at that point. -// We generally don't want to use this macro outside of C++20-only code, -// because using it conditionally in one language version only would make -// the ABI inconsistent. +# define _LIBCPP_NO_UNIQUE_ADDRESS [[__no_unique_address__]] # endif // c8rtomb() and mbrtoc8() were added in C++20 and C23. Support for these diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h index 35c12921e8ffa1..b4cbd1ddfa8deb 100644 --- a/libcxx/include/__type_traits/datasizeof.h +++ b/libcxx/include/__type_traits/datasizeof.h @@ -26,34 +26,22 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if __has_keyword(__datasizeof) || __has_extension(datasizeof) +// TODO: Enable this again once #94816 is fixed. +#if (__has_keyword(__datasizeof) || __has_extension(datasizeof)) && 0 template inline const size_t __datasizeof_v = __datasizeof(_Tp); #else -// NOLINTNEXTLINE(readability-redundant-preprocessor) This is https://llvm.org/PR64825 -# if __has_cpp_attribute(__no_unique_address__) template struct _FirstPaddingByte { - [[__no_unique_address__]] _Tp __v_; + _LIBCPP_NO_UNIQUE_ADDRESS _Tp __v_; char __first_padding_byte_; }; -# else -template ::value || !is_class<_Tp>::value> -struct _FirstPaddingByte : _Tp { - char __first_padding_byte_; -}; - -template -struct _FirstPaddingByte<_Tp, true> { - _Tp __v_; - char __first_padding_byte_; -}; -# endif // __has_cpp_attribute(__no_unique_address__) // _FirstPaddingByte<> is sometimes non-standard layout. Using `offsetof` is UB in that case, but GCC and Clang allow // the use as an extension. _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Winvalid-offsetof") +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Winvalid-offsetof") template inline const size_t __datasizeof_v = offsetof(_FirstPaddingByte<_Tp>, __first_padding_byte_); _LIBCPP_DIAGNOSTIC_POP diff --git a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp index 03dd0f6eac53a2..90463b0ac06e43 100644 --- a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp +++ b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp @@ -8,13 +8,25 @@ #include <__type_traits/datasizeof.h> #include +#include static_assert(std::__datasizeof_v == 1, ""); static_assert(std::__datasizeof_v == 2, ""); static_assert(std::__datasizeof_v == 4, ""); static_assert(std::__datasizeof_v == 8, ""); -struct OneBytePadding { +struct NonStandardLayout { + virtual ~NonStandardLayout(); +}; + +static_assert(!std::is_standard_layout::value, ""); +static_assert(std::__datasizeof_v == sizeof(void*), ""); + +struct Empty {}; + +static_assert(std::__datasizeof_v == 0, ""); + +struct OneBytePadding final { OneBytePadding() {} std::int16_t a; @@ -36,3 +48,9 @@ struct InBetweenPadding { }; static_assert(std::__datasizeof_v == 8, ""); + +struct NoDataButNoPadding { + OneBytePadding v; +}; + +static_assert(std::__datasizeof_v == 4, "");