[libcxx-commits] [libcxx] [libc++] Fix ABI break introduced by switching to _LIBCPP_COMPRESSED_PAIR (PR #154686)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri Aug 22 06:46:56 PDT 2025


================
@@ -148,6 +148,20 @@ ABI Affecting Changes
   comparison between shared libraries, since all RTTI has the correct visibility now. There is no behaviour change on
   Clang.
 
+- LLVM 20 contains an ABI break when
+  (1) using empty allocators which derive from the same base class, or
+  (2) having an object of the same type as an empty member in one of the following classes that could be layed out at
+      the beginnig of the object
+
+  (1) applies to ``unordered_map``, ``unordered_set``, ``unordered_multimap``, ``unordered_multiset``  and ``deque``.
+  (2) applies to the containers listed in (1) as well as ``map``, ``set``, ``multimap``, ``multiset``, ``list`` and
+      ``vector``.
+
+  Fixing this causes a regression in ``unique_ptr``. Specifically, constant evaluation fails when the deleter relies on
+  being value-initialized. If the deleter works if it is default initialized or is not trivially default constructible
+  it is not affected.
+
+  For more details see https://llvm.org/PR154146.
----------------
ldionne wrote:

```suggestion
- LLVM 20 contained an ABI break that can result in the size of ``std::unordered_{map,set,multimap,multiset}`` and ``std::deque`` to change 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>`` and ``Allocator<char>`` are both empty and contain the same base class).
  In addition, the layout of a user-defined type that:
    - contains one of the following containers: ``std::unordered_{map,set,multimap,multiset}``, ``std::deque``, ``std::map``, ``std::set``, ``std::multimap``, ``std::multiset``, ``std::list`` or ``std::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 struct, 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. This was caused by the usage of ``[[no_unique_address]]`` within some of libc++'s containers in a way that allowed subtle interactions with enclosing objects. This is fixed in LLVM 21 (returning to the LLVM 19 ABI), however that implies an ABI break from LLVM 20 to LLVM 21.

  Furthermore, fixing this causes a slight regression to constant evaluation support in ``std::unique_ptr``. Specifically, constant evaluation will now fail when the deleter relies on being value-initialized for constant-evaluation admissibility. If a default-initialized deleter can be used during constant evaluation, or if the default constructor is non-trivial, the ``unique_ptr`` is not affected by this regression. In particular, this regression does not impact any ``unique_ptr`` using the default deleter.

  For more details see https://llvm.org/PR154146.
```

https://github.com/llvm/llvm-project/pull/154686


More information about the libcxx-commits mailing list