[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