AK: Remove Variant<Ts...>::operator Variant<NewTs...>()

This is an interface to downcast(), which degrades errors into runtime
errors, and allows seemingly-correct-but-not-quite constructs like the
following to appear to compile, but fail at runtime:

    Variant<NonnullRefPtr<T>, U> foo = ...;
    Variant<RefPtr<T>, U> bar = foo;

The expectation here is that `foo` is converted to a RefPtr<T> if it
contains one, and remains a U otherwise, but in reality, the
NonnullRefPtr<T> variant is simply dropped on the floor, and the
resulting variant becomes invalid, failing the assertion in downcast().

This commit adds a Variant<Ts...>(Variant<NewTs...>) constructor that
ensures that no alternative can be left out at compiletime, for the
users that were using this interface for merely increasing the number of
alternatives (for instance, LibSQL's Value class).
This commit is contained in:
Ali Mohammad Pur 2021-12-25 02:12:54 +03:30 committed by Ali Mohammad Pur
parent 7d7950b322
commit 986d63466e
Notes: sideshowbarker 2024-07-17 22:11:25 +09:00

View file

@ -207,6 +207,18 @@ public:
return index_of<T>() != invalid_index;
}
template<typename... NewTs>
Variant(Variant<NewTs...>&& old) requires((can_contain<NewTs>() && ...))
: Variant(move(old).template downcast<Ts...>())
{
}
template<typename... NewTs>
Variant(const Variant<NewTs...>& old) requires((can_contain<NewTs>() && ...))
: Variant(old.template downcast<Ts...>())
{
}
template<typename... NewTs>
friend struct Variant;
@ -389,18 +401,6 @@ public:
return instance;
}
template<typename... NewTs>
explicit operator Variant<NewTs...>() &&
{
return downcast<NewTs...>();
}
template<typename... NewTs>
explicit operator Variant<NewTs...>() const&
{
return downcast<NewTs...>();
}
private:
static constexpr auto data_size = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, sizeof(Ts)...>()).max();
static constexpr auto data_alignment = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, alignof(Ts)...>()).max();