Skip to content

Conversation

@Quuxplusone
Copy link
Contributor

@Quuxplusone Quuxplusone commented Dec 19, 2025

This simplifies the codepaths after a4950fb. 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).

(Fixes #1885 in a different, shorter/correcter, way.)

Where P1144 is available, Abseil 20250127.0 has better performance than current Abseil trunk: i.e. trunk has regressed. This fixes that regression.

This simplifies the codepaths after a4950fb. 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).
@derekmauro
Copy link
Member

I agree with removing the Clang builtins given the reported bugs. However, as far as I can tell, std::is_trivially_relocatable and __cpp_lib_trivially_relocatable are not yet standardized, I would prefer not to speculate on the final API shape in Abseil's mainline.

Could we please remove the #if defined(__cpp_lib_trivially_relocatable) block and stick strictly to the std::is_trivially_copyable fallback for now?

@Quuxplusone
Copy link
Contributor Author

I agree with removing the Clang builtins given the reported bugs. However, as far as I can tell, std::is_trivially_relocatable and __cpp_lib_trivially_relocatable are not yet standardized, I would prefer not to speculate on the final API shape in Abseil's mainline.

__cpp_lib_trivially_relocatable is P1144's feature-test macro. It, and the API of P1144, haven't changed since P1144 support was introduced into Abseil two years ago (in my own #1625) nor since __is_trivially_relocatable(T) was introduced into Abseil four years ago in b6a1039. I have often used Abseil as a good example of the kinds of performance wins you can get from trivial-relocatability; it's easy to see these wins on Godbolt (which uses Abseil 20250127.0, which predates a4950fb, so you can still see these wins today even though Abseil trunk has lost them).

For a test case, you can use the code from https://godbolt.org/z/xaa98qxhz , where Abseil version 20250127.0 used to use memmove inside InlinedVector<unique_ptr<int>>::erase on my P1144 reference implementation, but Abseil trunk (due to a4950fb) no longer uses memmove.

Could we please remove the #if defined(__cpp_lib_trivially_relocatable) block and stick strictly to the std::is_trivially_copyable fallback for now?

That would be less buggy than the current post- a4950fb status quo, but Abseil would still not be getting the memmove optimizations when compiled with a P1144-compatible compiler. Getting those optimizations has been the point of patches like #1625, #1632, #1618; it is a shame to break those optimizations now.

Using P1144's features on systems that define them today isn't "speculating" — if C++29/32/... ever ships something different, or a second suitable-yet-differently-shaped API ever materializes, then Abseil could simply add an #elif branch conditioned on that other API's presence. In the meantime, re-enabling these optimizations (fixing a4950fb's brief regression versus Abseil 20250127.0) is appropriate IMO.

Note it's only these lines of code we're debating over:

#if defined(__cpp_lib_trivially_relocatable) // P1144
template <class T>
struct is_trivially_relocatable : std::is_trivially_relocatable<T> {
};
#else

Which is just, like, "if we have the feature then use it" (otherwise, emulate it).

@derekmauro
Copy link
Member

derekmauro commented Jan 13, 2026

Regardless of the current compiler support or the performance benefits, trivial relocatability is not currently in the C++26 working draft, relying on this macro effectively treats a proposal as a standard feature.

Even if P1144 is the, um, more useful approach, Abseil shouldn't claim support for a standard feature that doesn't legally exist yet. We should stick to the correct, non-speculative std::is_trivially_copyable baseline for now and revisit this in a couple of years, or whenever the feature is officially part of the standard.

@Quuxplusone
Copy link
Contributor Author

relying on this macro effectively treats a proposal as a standard feature

I'd say it's a "non-standard extension" — that's why you have to place the code under the guard macro rather than just assume it's OK to use on all platforms. I don't see this as fundamentally different from e.g. Abseil's conditional support for gsl::Owner.

However, while e.g. Folly and Parlay are happy to guard their usage directly with __cpp_lib_trivially_relocatable, there is precedent for using your own guard macro: you can see here that Ste||ar HPX used to test __cpp_lib_trivially_relocatable (that identifier remains in a comment) but has switched to testing HPX_HAVE_P1144_RELOCATE_AT instead. The downside is that someone has to #define that macro at build time; it's not just set automatically.

(1) Suppose we replace

#if defined(__cpp_lib_trivially_relocatable) // P1144

with

#if defined(ABSL_HAVE_P1144_LIBRARY_API)

and then add a comment somewhere, similar to how you do ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI today, indicating that this macro is not defined but people who want it should define it?

(2) Or, again looking at how Abseil generally does this conditional-support/conditional-extension stuff — in Abseil's attributes.h — suppose you define something in there like

#define ABSL_IS_TRIVIALLY_RELOCATABLE std::is_trivially_copyable

and then guard that definition with compiler-support guards, e.g.

#if __cpp_lib_trivially_relocatable // P1144
#define ABSL_IS_TRIVIALLY_RELOCATABLE std::is_trivially_relocatable
#else
#define ABSL_IS_TRIVIALLY_RELOCATABLE std::is_trivially_copyable
#endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: builtin __is_trivially_relocatable is deprecated

2 participants