Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions libcxx/docs/ReleaseNotes/20.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ LLVM 21
ABI Affecting Changes
---------------------

- The ABI breaks for removing undefined behaviour in ``std::forward_list``, ``std::list``, ``std::map``, ``std::set``,
``std::multimap``, ``std::multiset``, ``std::unordered_map``, ``std::unordered_set``, ``std::unordered_multimap`` and
``std::unordered_multiset`` are now applied unconditionally. This only affects fancy pointers which have a different
value representation when pointing at the base of an internal node type instead of the type itself. A size or
alignment difference is diagnosed, but more subtle ABI breaks may result in unexpected behaviour.

- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. The ABI impact is:

- When using the Itanium ABI (most non-MSVC platforms), empty types are now placed at the beginning of the enclosing
Expand Down
15 changes: 11 additions & 4 deletions libcxx/include/__hash_table
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,18 @@ struct __hash_node_base {
typedef __hash_node_base __first_node;
typedef __rebind_pointer_t<_NodePtr, __first_node> __node_base_pointer;
typedef _NodePtr __node_pointer;

#if defined(_LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB)
typedef __node_base_pointer __next_pointer;
#else
typedef __conditional_t<is_pointer<__node_pointer>::value, __node_base_pointer, __node_pointer> __next_pointer;

// TODO(LLVM 22): Remove this check
#ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB
// TODO(LLVM 22): Remove
#ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB

Here and below.

static_assert(sizeof(__node_base_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) ==
_LIBCPP_ALIGNOF(__node_pointer),
"It looks like you are using std::__hash_table (an implementation detail for the unordered containers) "
"with a fancy pointer type that thas a different representation depending on whether it points to a "
"__hash_table base pointer or a __hash_table node pointer (both of which are implementation details of "
"the standard library). This means that your ABI is being broken between LLVM 19 and LLVM 20. If you "
"don't care about your ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to "
"silence this diagnostic.");
#endif

__next_pointer __next_;
Expand Down
20 changes: 11 additions & 9 deletions libcxx/include/__tree
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,18 @@ struct __tree_node_base_types {

typedef __tree_end_node<__node_base_pointer> __end_node_type;
typedef __rebind_pointer_t<_VoidPtr, __end_node_type> __end_node_pointer;
#if defined(_LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB)
typedef __end_node_pointer __parent_pointer;
#else
typedef __conditional_t< is_pointer<__end_node_pointer>::value, __end_node_pointer, __node_base_pointer>
__parent_pointer;

// TODO(LLVM 22): Remove this check
#ifndef _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB
static_assert(sizeof(__node_base_pointer) == sizeof(__end_node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) ==
_LIBCPP_ALIGNOF(__end_node_pointer),
"It looks like you are using std::__tree (an implementation detail for (multi)map/set) with a fancy "
"pointer type that thas a different representation depending on whether it points to a __tree base "
"pointer or a __tree node pointer (both of which are implementation details of the standard library). "
"This means that your ABI is being broken between LLVM 19 and LLVM 20. If you don't care about your "
"ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to silence this "
"diagnostic.");
#endif

private:
Expand Down Expand Up @@ -605,12 +612,7 @@ public:
typedef _Tp __node_value_type;
typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer;
typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer;
#if defined(_LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB)
typedef typename __base::__end_node_pointer __iter_pointer;
#else
typedef __conditional_t< is_pointer<__node_pointer>::value, typename __base::__end_node_pointer, __node_pointer>
__iter_pointer;
#endif

private:
static_assert(!is_const<__node_type>::value, "_NodePtr should never be a pointer to const");
Expand Down
28 changes: 14 additions & 14 deletions libcxx/include/forward_list
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,20 @@ struct __forward_node_traits {
typedef __rebind_pointer_t<_NodePtr, __begin_node> __begin_node_pointer;
typedef __rebind_pointer_t<_NodePtr, void> __void_pointer;

#if defined(_LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB)
typedef __begin_node_pointer __iter_node_pointer;
#else
typedef __conditional_t<is_pointer<__void_pointer>::value, __begin_node_pointer, __node_pointer> __iter_node_pointer;
// TODO(LLVM 22): Remove this check
#ifndef _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB
static_assert(sizeof(__begin_node_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__begin_node_pointer) ==
_LIBCPP_ALIGNOF(__node_pointer),
"It looks like you are using std::forward_list with a fancy pointer type that thas a different "
"representation depending on whether it points to a forward_list base pointer or a forward_list node "
"pointer (both of which are implementation details of the standard library). This means that your ABI "
"is being broken between LLVM 19 and LLVM 20. If you don't care about your ABI being broken, define "
"the _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB macro to silence this diagnostic.");
#endif

typedef __conditional_t<is_same<__iter_node_pointer, __node_pointer>::value, __begin_node_pointer, __node_pointer>
__non_iter_node_pointer;

_LIBCPP_HIDE_FROM_ABI static __iter_node_pointer __as_iter_node(__iter_node_pointer __p) { return __p; }
_LIBCPP_HIDE_FROM_ABI static __iter_node_pointer __as_iter_node(__non_iter_node_pointer __p) {
return static_cast<__iter_node_pointer>(static_cast<__void_pointer>(__p));
_LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__begin_node_pointer __p) { return __p; }
_LIBCPP_HIDE_FROM_ABI static __begin_node_pointer __as_iter_node(__node_pointer __p) {
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__p));
}
};

Expand Down Expand Up @@ -351,10 +353,9 @@ class _LIBCPP_TEMPLATE_VIS __forward_list_iterator {
typedef __forward_node_traits<_NodePtr> __traits;
typedef typename __traits::__node_pointer __node_pointer;
typedef typename __traits::__begin_node_pointer __begin_node_pointer;
typedef typename __traits::__iter_node_pointer __iter_node_pointer;
typedef typename __traits::__void_pointer __void_pointer;

__iter_node_pointer __ptr_;
__begin_node_pointer __ptr_;

_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const {
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_));
Expand Down Expand Up @@ -417,10 +418,9 @@ class _LIBCPP_TEMPLATE_VIS __forward_list_const_iterator {
typedef typename __traits::__node_type __node_type;
typedef typename __traits::__node_pointer __node_pointer;
typedef typename __traits::__begin_node_pointer __begin_node_pointer;
typedef typename __traits::__iter_node_pointer __iter_node_pointer;
typedef typename __traits::__void_pointer __void_pointer;

__iter_node_pointer __ptr_;
__begin_node_pointer __ptr_;

_LIBCPP_HIDE_FROM_ABI __begin_node_pointer __get_begin() const {
return static_cast<__begin_node_pointer>(static_cast<__void_pointer>(__ptr_));
Expand Down
Loading
Loading