[all-commits] [llvm/llvm-project] a2f2f1: [libc++] Fix ABI break introduced by switching to ...

Nikolas Klauser via All-commits all-commits at lists.llvm.org
Mon Aug 25 23:36:46 PDT 2025


  Branch: refs/heads/release/21.x
  Home:   https://github.com/llvm/llvm-project
  Commit: a2f2f1aa46fe0f42273a10a062b2a96439bf1a71
      https://github.com/llvm/llvm-project/commit/a2f2f1aa46fe0f42273a10a062b2a96439bf1a71
  Author: Nikolas Klauser <nikolasklauser at berlin.de>
  Date:   2025-08-25 (Mon, 25 Aug 2025)

  Changed paths:
    M libcxx/docs/ReleaseNotes/21.rst
    M libcxx/include/__memory/compressed_pair.h
    M libcxx/include/string
    M libcxx/test/libcxx/containers/associative/map/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/associative/set/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/associative/unord.map/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/associative/unord.set/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/sequences/deque/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/sequences/list/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/sequences/vector.bool/abi.compile.pass.cpp
    M libcxx/test/libcxx/containers/sequences/vector/abi.compile.pass.cpp
    M libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/default.pass.cpp
    M libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/nullptr.pass.cpp
    M libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer.pass.cpp

  Log Message:
  -----------
  [libc++] Fix ABI break introduced by switching to _LIBCPP_COMPRESSED_PAIR (#154686)

LLVM 20 contained an ABI break that can result in the size of
`std::unordered_{map,set,multimap,multiset}` and `std::deque` changing
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 on Clang (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.

Note that there is currently no way to realistically fix this ABI break
on GCC, therefore GCC will remain on the ABI introduced in LLVM 19. That
also means that Clang and GCC will have a slightly different ABI for the
small subset of types listed above until we are able to apply the same
fix we did with Clang on GCC.

We fix this regression by surrounding the members of the
`_LIBCPP_COMPRESSED_PAIR` with an anonymous struct. This restricts the
shifting of empty types to the front of the `_LIBCPP_COMPRESSED_PAIR`
instead of throughout the surrounding object. This "frees up" the zero
offset to contain another object of the same type, restoring the ability
to perform EBO or to elide the storage for a type with
`[[no_unique_address]]` in the enclosing (user-defined) struct.

Fixes #154146

Co-authored-by: Louis Dionne <ldionne.2 at gmail.com>



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list