[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
Fri Oct 27 10:09:52 PDT 2023


jiixyj wrote:

> * 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. :(

I managed to fix the code duplication by making `[[no_unique_address]]` conditional with `std::conditional`. So the current layout looks like this:

```c++
template <bool NoUnique, class Tp>
class conditional_no_unique_address {
  struct unique {
    Tp v;
  };
  struct no_unique {
    [[no_unique_address]] Tp v;
  };

public:
  using type = std::conditional<NoUnique, no_unique, unique>::type;
}

// Returns true iff "has value" can be stuffed into the tail of the union.
template <class Union>
constexpr bool can_stuff_tail();

template <class Tp, class Err>
class expected_base {
  union union_t {
    [[no_unique_address]] Tp val;
    [[no_unique_address]] Err unex;
  };

  struct repr {
  private:
    // If "has value" can be stuffed into the tail, this should be
    // `[[no_unique_address]]`, otherwise not.
    [[no_unique_address]] conditional_no_unique_address<
        can_stuff_tail<union_t>(), union_t>::type union_;
    [[no_unique_address]] bool has_val_;
  };

protected:
  // If "has value" can be stuffed into the tail, this must _not_ be
  // `[[no_unique_address]]` so that we fill out the complete `expected` object.
  [[no_unique_address]] conditional_no_unique_address<
      !can_stuff_tail<union_t>(), repr>::type repr_;
};

template <class Tp, class Err>
class expected : private expected_base<Tp, Err> {};
```

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


More information about the libcxx-commits mailing list