Skip to content

Commit 2f30123

Browse files
committed
[libc++] Replace __compressed_pair with [[no_unique_address]]
1 parent 583129d commit 2f30123

File tree

19 files changed

+580
-606
lines changed

19 files changed

+580
-606
lines changed

Diff for: libcxx/docs/ReleaseNotes/19.rst

+6-2
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ What's New in Libc++ 19.0.0?
3737

3838
Implemented Papers
3939
------------------
40+
4041
- P2637R3 - Member ``visit``
4142

4243

4344
Improvements and New Features
4445
-----------------------------
45-
TODO
4646

47+
- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``, resulting in reduced
48+
compile times and smaller debug information as well as better code gen if optimizations are disabled.
4749

4850
Deprecations and Removals
4951
-------------------------
@@ -91,8 +93,10 @@ TODO
9193

9294
ABI Affecting Changes
9395
---------------------
94-
TODO
9596

97+
- The internal structure ``__compressed_pair`` has been replaced with ``[[no_unique_address]]``. This change results in
98+
empty final types being placed at the beginning of the object instead of where the beginning of the
99+
``__compressed_pair`` subobject was. This is only observable by checking the address of the subobject.
96100

97101
Build System Changes
98102
--------------------

Diff for: libcxx/include/__config

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666

6767
# define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y
6868
# define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y)
69+
# define _LIBCPP_CONCAT3(X, Y, Z) _LIBCPP_CONCAT(X, _LIBCPP_CONCAT(Y, Z))
6970

7071
# if __STDC_HOSTED__ == 0
7172
# define _LIBCPP_FREESTANDING
@@ -174,6 +175,13 @@
174175
// The implementation moved to the header, but we still export the symbols from
175176
// the dylib for backwards compatibility.
176177
# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10
178+
// Historically, libc++ used a type called `__compressed_pair` to reduce storage need in cases of empty types (e.g. an
179+
// empty allocator in std::vector). We switched to using `[[no_unique_address]]`. However, for ABI compatibility reasons
180+
// we had to add artificial padding in a few places.
181+
//
182+
// This setting disables the addition of such artificial padding, leading to a more optimal
183+
// representation for several types.
184+
# define _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING
177185
# elif _LIBCPP_ABI_VERSION == 1
178186
# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF))
179187
// Enable compiling copies of now inline methods into the dylib to support

Diff for: libcxx/include/__functional/function.h

+14-13
Original file line numberDiff line numberDiff line change
@@ -141,45 +141,46 @@ class __default_alloc_func;
141141

142142
template <class _Fp, class _Ap, class _Rp, class... _ArgTypes>
143143
class __alloc_func<_Fp, _Ap, _Rp(_ArgTypes...)> {
144-
__compressed_pair<_Fp, _Ap> __f_;
144+
_LIBCPP_COMPRESSED_PAIR(_Fp, __func_, _Ap, __alloc_);
145145

146146
public:
147147
typedef _LIBCPP_NODEBUG _Fp _Target;
148148
typedef _LIBCPP_NODEBUG _Ap _Alloc;
149149

150-
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __f_.first(); }
150+
_LIBCPP_HIDE_FROM_ABI const _Target& __target() const { return __func_; }
151151

152152
// WIN32 APIs may define __allocator, so use __get_allocator instead.
153-
_LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __f_.second(); }
153+
_LIBCPP_HIDE_FROM_ABI const _Alloc& __get_allocator() const { return __alloc_; }
154154

155-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f)
156-
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple()) {}
155+
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f) : __func_(std::move(__f)), __alloc_() {}
157156

158-
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a)
159-
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(__a)) {}
157+
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, const _Alloc& __a) : __func_(__f), __alloc_(__a) {}
160158

161159
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(const _Target& __f, _Alloc&& __a)
162-
: __f_(piecewise_construct, std::forward_as_tuple(__f), std::forward_as_tuple(std::move(__a))) {}
160+
: __func_(__f), __alloc_(std::move(__a)) {}
163161

164162
_LIBCPP_HIDE_FROM_ABI explicit __alloc_func(_Target&& __f, _Alloc&& __a)
165-
: __f_(piecewise_construct, std::forward_as_tuple(std::move(__f)), std::forward_as_tuple(std::move(__a))) {}
163+
: __func_(std::move(__f)), __alloc_(std::move(__a)) {}
166164

167165
_LIBCPP_HIDE_FROM_ABI _Rp operator()(_ArgTypes&&... __arg) {
168166
typedef __invoke_void_return_wrapper<_Rp> _Invoker;
169-
return _Invoker::__call(__f_.first(), std::forward<_ArgTypes>(__arg)...);
167+
return _Invoker::__call(__func_, std::forward<_ArgTypes>(__arg)...);
170168
}
171169

172170
_LIBCPP_HIDE_FROM_ABI __alloc_func* __clone() const {
173171
typedef allocator_traits<_Alloc> __alloc_traits;
174172
typedef __rebind_alloc<__alloc_traits, __alloc_func> _AA;
175-
_AA __a(__f_.second());
173+
_AA __a(__alloc_);
176174
typedef __allocator_destructor<_AA> _Dp;
177175
unique_ptr<__alloc_func, _Dp> __hold(__a.allocate(1), _Dp(__a, 1));
178-
::new ((void*)__hold.get()) __alloc_func(__f_.first(), _Alloc(__a));
176+
::new ((void*)__hold.get()) __alloc_func(__func_, _Alloc(__a));
179177
return __hold.release();
180178
}
181179

182-
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT { __f_.~__compressed_pair<_Target, _Alloc>(); }
180+
_LIBCPP_HIDE_FROM_ABI void destroy() _NOEXCEPT {
181+
__func_.~_Fp();
182+
__alloc_.~_Alloc();
183+
}
183184

184185
_LIBCPP_HIDE_FROM_ABI static void __destroy_and_delete(__alloc_func* __f) {
185186
typedef allocator_traits<_Alloc> __alloc_traits;

0 commit comments

Comments
 (0)