[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 23:02:02 PDT 2023


jiixyj wrote:

One think I'm still unsure about is the layout of the union itself. Currently, it looks like this:

```c++
template <class Val, class Err>
union {
  Val val_;
  Err unex_;
};

template <class Val, class Err>
requires(is_trivially_move_constructible_v<Val> && is_trivially_move_constructible_v<Err>)
union {
  [[no_unique_address]] Val val_;
  [[no_unique_address]] Err unex_;
};
```

...i.e. tail padding is only ever reused if _both_ types are trivially move constructible. I think this was done to make the layout compatible with GCC (and possibly future changes to the standard/Itanium ABI). <https://github.com/itanium-cxx-abi/cxx-abi/issues/107> has some good discussion.

But I wonder, why do the types need to be trivially move constructible? Wouldn't nothrow move constructible be enough? The problematic case seems to be this one: https://godbolt.org/z/1xEo1njGP There, type `Foo` satisfies all requirements (<https://eel.is/c++draft/expected#object.assign-9.3>) to be assignable to `expected<Bar>`, but GCC doesn't to the guaranteed copy elision into the `[[no_unique_address]]` member so the operation throws (!).

To fix this, wouldn't this work instead of the current approach?

```c++
template <class Val, class Err>
union u {
  Val val_;
  Err unex_;
};

template <class Val, class Err>
requires is_nothrow_move_constructible_v<Val>
union<Val, Err> u {
  [[no_unique_address]] Val val_;
  Err unex_;
};

template <class Val, class Err>
requires is_nothrow_move_constructible_v<Err>
union<Val, Err> u {
  Val val_;
  [[no_unique_address]] Err unex_;
};

template <class Val, class Err>
requires(is_nothrow_move_constructible_v<Val> && is_nothrow_move_constructible_v<Err>)
union<Val, Err> u {
  [[no_unique_address]] Val val_;
  [[no_unique_address]] Err unex_;
};
```

There is a bit of combinatorial explosion going on, but this the best layout I could come up with that is still compatible with GCC.

https://github.com/llvm/llvm-project/pull/69673


More information about the libcxx-commits mailing list