[libcxx-commits] [libcxx] [libc++] Ensure that `std::expected` has no tail padding (PR #69673)
Jan Kokemüller via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Oct 24 22:45:16 PDT 2023
jiixyj wrote:
I've implemented the layout from comment <https://github.com/llvm/llvm-project/pull/69673#issuecomment-1776570398> and I think it works pretty well!
There are now two layouts:
- In case the "has value" bool is stuffable into the tail padding of the union, the whole "repr" class needs to be transparently replaced on `emplace()`/`swap()` etc. Let's call it the "TRR" (transparently replaceable "repr") layout.
- In case the "has value" bool is not stuffable into the tail padding of the union, _only_ the union member must be transparently replaced and the "has value" flag must be adjusted manually. Let's call that layout "TRU" (transparently replaceable "union")
Some note:
- I moved all "union" and "repr" types out of the "expected" class.
- Sadly, there is some code duplication going on since there are now _two_ repr classes instead of just one. :(
- For "TRU", the "repr" class offers some member functions to help with union destruction/construction: `__destroy_union` and `__construct_union`. Those member functions also do the adjustment of the "has bool" flag.
- GCC does not like to do guaranteed copy elision into `[[no_unique_address]]` members (<https://github.com/itanium-cxx-abi/cxx-abi/issues/107>), so to implement expected's copy constructors there need to be two helper functions that do guaranteed copy elision, which may look weird at first:
- TRU:
```c++
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __expected_union_t<_Tp, _Err>
__make_union(bool __has_val, _OtherUnion&& __other)
{
if (__has_val)
return __expected_union_t<_Tp, _Err>(in_place, std::forward<_OtherUnion>(__other).__val_);
else
return __expected_union_t<_Tp, _Err>(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
```
- TRR:
```c++
template <class _OtherUnion>
_LIBCPP_HIDE_FROM_ABI static constexpr __repr __make_repr(bool __has_val, _OtherUnion&& __other)
{
if (__has_val)
return __repr(in_place, std::forward<_OtherUnion>(__other).__val_);
else
return __repr(unexpect, std::forward<_OtherUnion>(__other).__unex_);
}
```
- `__expected_base` provides two helper functions `__destroy` and `__construct` which are called by expected's members instead of `std::destroy_at` and `std::construct_at`. The helpers then either transparently replace the repr (for TRR) or the union (for TRU).
https://github.com/llvm/llvm-project/pull/69673
More information about the libcxx-commits
mailing list