-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Description
Hi @llvm/libcxx-vendors,
This issue is not a traditional issue. It is a communication to vendors about an upcoming (and past) ABI break in some of libc++'s container types. It was recently brought to our attention in #154146 that an ABI break had been introduced in various container types from LLVM 19 to LLVM 20, released on March 4th 2025.
There are two ways this ABI break can be witnessed:
- The size of
std::unordered_{map,set,multimap,multiset}
andstd::deque
when used with an allocator type that is empty and contains a base class that is the same across rebound allocator instantiations (e.g.Allocator<int>
andAllocator<char>
are both empty and contain the same base class) changed between LLVM 19 and LLVM 20. - The layout of a user-defined type (say
Foo
) that:- contains a member of type
std::unordered_{map,set,multimap,multiset}
,std::deque
,std::map
,std::set
,std::multimap
,std::multiset
,std::list
orstd::vector
, and - passes an empty allocator, comparator or hasher type to that container, and
- has a member of that same empty allocator, comparator or hasher type inside the enclosing type
Foo
, and - that member is either marked with
[[no_unique_address]]
or optimized out via the EBO (empty base optimization) technique
saw its size increase from LLVM 19 to LLVM 20.
- contains a member of type
This ABI break relates to the usage of [[no_unique_address]]
within these containers to replace the usage of an old "compressed pair" emulation, which allowed subtle interactions with enclosing objects. See this and this for a more in-depth discussion of the issue. We will be fixing this in LLVM 21's libc++ when using a supported Clang compiler, returning to the LLVM 19 ABI. However, that implies an ABI break from LLVM 20 to LLVM 21. Furthermore, there is currently no way to realistically fix this ABI break when using the GCC compiler until an underlying compiler bug is fixed, therefore libc++ will remain on the ABI introduced in LLVM 20 when used with GCC. That also means that libc++ will provide a slightly different ABI when used with Clang and GCC (for the small subset of types listed above) until we are able to fix that difference.
We are still discussing whether we will be producing a fix for the already-released LLVM 20.x series. Such a fix might appear in the form of a new LLVM 20.2.y release, however this hasn't been decided yet. Please refer to this issue for updates.
The current situation puts us in a challenging position with difficult tradeoffs to make on all sides. We reached the above plan after a lot of discussion with @philnik777 and also consulted with @AaronBallman on the matter. In particular, we decided that making this ABI fix on Clang despite it not being possible with GCC is an acceptable tradeoff given that we support GCC on a best-effort basis. We decided to optimize for the most important use case (Clang / libc++) being fixed in a timely fashion. Reintroducing the original compressed pair emulation we originally had was also considered, however we decided not to opt for that option since it would require a massive refactoring that we couldn't do without seriously impacting the LLVM 21 release schedule (or missing it), and would also significantly regress compilation times and debug info sizes. We also believe that the scope of this ABI break, while large, is mitigated by some factors like the need for users to use [[no_unique_address]]
(which is not mainstream), or to have an allocator with very specific properties, and for these uses to be relevant in their own ABIs (i.e. not a local-only usage). For all of these reasons, we think that the current decision to fix this forward on Clang with our planned approach achieves the best tradeoff.
Please watch this issue for updates on this topic and please limit discussion to necessary questions or inquiries about the strategy outlined above. Please direct technical discussions on the bug itself towards the original bug report.