[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
       
    Mon Oct 23 22:44:39 PDT 2023
    
    
  
jiixyj wrote:
> Perhaps we should use a mixed strategy:
> 
>     * when the `bool` flag lives in the tail padding of the union, the repr strategy should be used, and `expected` shouldn't have reusable tail padding,
> 
>     * otherwise, however, we should make the tail padding of `expected` (if any) reusable.
> 
> 
> It's painful that we have no `[[no_unique_address(condition)]]` yet.
What do you think about this:
```c++
#include <expected>
#include <iostream>
#include <memory>
#include <optional>
template <typename Val, typename Err>
union expected_union {
    [[no_unique_address]] Val val;
    [[no_unique_address]] Err unex;
};
template <typename Val, typename Err, bool StuffTail = false>
struct expected_repr {
   private:
    expected_union<Val, Err> union_;
    [[no_unique_address]] bool has_val_;
};
template <typename Val, typename Err>
struct expected_repr<Val, Err, true> {
   private:
    [[no_unique_address]] expected_union<Val, Err> union_;
    [[no_unique_address]] bool has_val_;
};
template <typename Val, typename Err,  //
          typename Repr = expected_repr<Val, Err, true>,
          typename Union = expected_union<Val, Err>>
concept tail_stuffable = sizeof(Repr) == sizeof(Union);
template <typename Val, typename Err>
struct expected_base {
   protected:
    [[no_unique_address]] expected_repr<Val, Err, false> repr_;
};
template <typename Val, typename Err>
    requires tail_stuffable<Val, Err>
struct expected_base<Val, Err> {
   protected:
    expected_repr<Val, Err, true> repr_;
};
template <typename Val, typename Err>
struct expected : private expected_base<Val, Err> {};
```
https://godbolt.org/z/5oj6TjTGd
You would have two `repr` types, depending on whether the bool flag can live in the union's tail padding or not, and switch between them with inheritance (sort of emulating conditional `[[no_unique_address]]`).
What I like about this is that you don't even need something like `std::__libcpp_datasize`. You can just ask the first `repr` type: "Can the `bool` be stuffed in your tail?"
In the "tail padding" case you would `std::destruct_at`/`std::construct_at` the whole `repr`, including the "has value" flag. In the "normal" case you would only `std::destruct_at`/`std::construct_at` the union and set the "has value" flag manually.
I'll try to implement this to see how bad it is regarding code complexity. But I'm optimistic!
https://github.com/llvm/llvm-project/pull/69673
    
    
More information about the libcxx-commits
mailing list