[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