From a98ebff043cd9f9d9d412c643942993b82a3de1b Mon Sep 17 00:00:00 2001 From: Arthur O'Dwyer Date: Thu, 18 Dec 2025 17:52:35 -0500 Subject: [PATCH] Remove all attempts to use Clang builtins for trivial relocatability This simplifies the codepaths after a4950fba. We can't use Clang's current `__builtin_is_cpp_trivially_relocatable(T)` for the same reason we continue to be unable to use Clang's current `__is_trivially_relocatable(T)`: it returns true for polymorphic types and other types that aren't trivially relocatable in the Abseil/Folly/P1144 sense. We use memcpy for relocation; we use relocation to implement InlineVector::erase and InlineVector::swap. So, as the comment says, we care about wonky assignment as well as wonky copy-construction or destruction. Use the public (not private/compiler-builtin!) API of P1144 wherever it's available. Never use the Clang builtins otherwise. Always fall back to the public (not private/compiler-builtin!) std::is_trivially_copyable when P1144 isn't available. Remove references to P2786; it is not part of C++26 anymore, and even if it were, Abseil couldn't use it, because P2786 ignored move-assignment and also permitted "relocation" to fix up vptrs (which memcpy never does). --- absl/meta/type_traits.h | 92 +++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index 59eb38ba816..c6df9a205d8 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -347,17 +347,11 @@ using swap_internal::Swap; // absl::is_trivially_relocatable // -// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2786r11.html -// // Detects whether a type is known to be "trivially relocatable" -- meaning it // can be relocated from one place to another as if by memcpy/memmove. // This implies that its object representation doesn't depend on its address, // and also none of its special member functions do anything strange. // -// Note that when relocating the caller code should ensure that if the object is -// polymorphic, the dynamic type is of the most derived type. Padding bytes -// should not be copied. -// // This trait is conservative. If it's true then the type is definitely // trivially relocatable, but if it's false then the type may or may not be. For // example, std::vector is trivially relocatable on every known STL @@ -369,59 +363,49 @@ using swap_internal::Swap; // if constexpr (absl::is_trivially_relocatable::value) { // memcpy(new_location, old_location, sizeof(T)); // } else { -// new(new_location) T(std::move(*old_location)); +// ::new(new_location) T(std::move(*old_location)); // old_location->~T(); // } // -// Upstream documentation: -// -// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__builtin_is_cpp_trivially_relocatable -// -// Clang on Windows has the builtin, but it falsely claims types with a -// user-provided destructor are trivial (http://b/275003464). So we opt out -// there. -// -// TODO(b/275003464): remove the opt-out once the bug is fixed. -// -// Starting with Xcode 15, the Apple compiler will falsely say a type -// with a user-provided move constructor is trivially relocatable -// (b/324278148). We will opt out without a version check, due to -// the fluidity of Apple versions. -// -// TODO(b/324278148): If all versions we use have the bug fixed, then -// remove the condition. -// -// Clang on all platforms fails to detect that a type with a user-provided -// move-assignment operator is not trivially relocatable so we also check for -// is_trivially_move_assignable for Clang. -// -// TODO(b/325479096): Remove the Clang is_trivially_move_assignable version once -// Clang's behavior is fixed. -// -// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not -// work with NVCC either. -#if ABSL_HAVE_BUILTIN(__builtin_is_cpp_trivially_relocatable) -// https://github.com/llvm/llvm-project/pull/127636#pullrequestreview-2637005293 -// In the current implementation, __builtin_is_cpp_trivially_relocatable will -// only return true for types that are trivially relocatable according to the -// standard. Notably, this means that marking a type [[clang::trivial_abi]] aka -// ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI will have no effect on this trait. +// Abseil's definition of trivial relocatability matches standards +// proposal P1144: we require that trivial relocation can be achieved +// by memcpy/memmove without additional fixup, and we use trivial +// relocation (memcpy/memmove) not only for vector reallocation (where +// it replaces a series of move-constructions and destructions) +// but also for InlineVector::erase and InlineVector::swap (where it +// replaces a series of one move-construction, several move-assignments, +// and one destruction). +// +// Mainline Clang provides two builtins, neither of which is suitable +// for Abseil. +// +// __is_trivially_relocatable(T) gives a deprecation warning. +// __is_trivially_relocatable(T) wrongly gives true on Windows +// for types with non-trivial destructors (b/275003464). +// __is_trivially_relocatable(T) wrongly gives true in Xcode 15 +// for types with non-trivial move-assignment operators (b/324278148). +// +// __builtin_is_cpp_trivially_relocatable(T) wrongly gives true +// on all platforms for types with non-trivial move-assignment operators +// (b/325479096). +//__builtin_is_cpp_trivially_relocatable(T) wrongly gives true +// on non-Apple-ARM64e platforms for polymorphic types. +// __builtin_is_cpp_trivially_relocatable(T) wrongly gives false +// on all platforms for types marked [[clang::trivial_abi]] a.k.a. +// ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI. +// +// According to https://github.com/abseil/abseil-cpp/issues/1479, +// NVCC gives true for __has_builtin(__is_trivially_relocatable), +// but then can't parse __is_trivially_relocatable(T). +// +// Mainline Clang's builtins are never suitable for Abseil's purposes. +// But if we detect that the library provides P1144's public API, +// then we can use that public type trait without fear. +// +#if defined(__cpp_lib_trivially_relocatable) // P1144 template -struct is_trivially_relocatable - : std::integral_constant { +struct is_trivially_relocatable : std::is_trivially_relocatable { }; -#elif ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && defined(__clang__) && \ - !(defined(_WIN32) || defined(_WIN64)) && !defined(__APPLE__) && \ - !defined(__NVCC__) -// https://github.com/llvm/llvm-project/pull/139061 -// __is_trivially_relocatable is deprecated. -// TODO(b/325479096): Remove this case. -template -struct is_trivially_relocatable - : std::integral_constant< - bool, std::is_trivially_copyable::value || - (__is_trivially_relocatable(T) && - std::is_trivially_move_assignable::value)> {}; #else // Otherwise we use a fallback that detects only those types we can feasibly // detect. Any type that is trivially copyable is by definition trivially