Weird `std::variant::operator==` error with clang + libc++ and specific number of variants

3 weeks ago 21
ARTICLE AD BOX

This is super weird and most likely a clang bug, but I want to be sure first, to avoid spamming devs with invalid issues.

I've distilled my use case to a simple example, where clang produces the error, that I'm pretty sure should not be there. Weirdly enough, if I tinker with the number of alternatives the issue miraculously disappears. Other compilers don't emit any errors, as well as clang with libstdc++ (live on godbolt.com).

// Set 1/2/3 to pick different use cases #define USE_CASE 1 #include <vector> #include <variant> struct Array; struct A1 { auto operator<=>(const A1 &) const = default; }; struct A2 { auto operator<=>(const A2 &) const = default; }; struct A3 { auto operator<=>(const A3 &) const = default; }; struct A4 { auto operator<=>(const A4 &) const = default; }; struct A5 { auto operator<=>(const A5 &) const = default; }; struct A6 { auto operator<=>(const A6 &) const = default; }; struct A7 { auto operator<=>(const A7 &) const = default; }; struct A8 { auto operator<=>(const A8 &) const = default; }; struct A9 { auto operator<=>(const A9 &) const = default; }; using Var1 = std::variant< A1 , A2 , A3 , A4 , A5 , A6 , A9 , Array >; struct Array : public std::vector<Var1> { using vector::vector; }; #if USE_CASE == 1 // This fails using Var2 = std::variant< A1 , A2 , A3 , A4 , A5 , A6 , A7 , Array >; #elif USE_CASE == 2 // This does not fail using Var2 = std::variant< A1 , A2 , A3 , A4 , A5 , A6 //, A7 , Array >; #elif USE_CASE == 3 // This does not fail using Var2 = std::variant< A1 , A2 , A3 , A4 , A5 , A6 , A7 , A8 , Array >; #endif static_assert(std::equality_comparable<Var2>); int main() { constexpr bool foo = Var2{} == Var2{}; return 0; }

Only if USE_CASE is 1 clang has issues. In two other cases, when some alternative is removed or added everything is fine. Weirdly, std::equality_comparable<Var2> always produces true, hinting at trickery. Seems like 8 is some magic number (optimization within libc++?).

Update:

Thanks to T.C. the test case was greatly simplified (live on godbolt.com):

#include <vector> #include <variant> struct Array; struct A1 { auto operator<=>(const A1 &) const = default; }; struct A2 { auto operator<=>(const A2 &) const = default; }; using Var1 = std::variant< A1 , Array >; struct Array : public std::vector<Var1> { using vector::vector; }; // This fails using Var2 = std::variant< A2 , Array >; static_assert(std::equality_comparable<Var2>); int main() { constexpr bool foo = Var2{} == Var2{}; return 0; }

And thanks to feedback from 0___________ the bug was reported.

Read Entire Article