diff --git a/llvm/include/llvm/ADT/DenseMapInfo.h b/llvm/include/llvm/ADT/DenseMapInfo.h --- a/llvm/include/llvm/ADT/DenseMapInfo.h +++ b/llvm/include/llvm/ADT/DenseMapInfo.h @@ -290,6 +290,32 @@ } }; +namespace detail { +// Helpers for DenseMapInfo + +// Returns a pointer to std::get(Val), where Index is not constant. +template +static const void *variantGetDynamic(const V &Val, int Index, + std::index_sequence) { + const void *Result = nullptr; + unsigned I = 0; + (((I++ == Index) ? (Result = &std::get(Val), true) : false) || ...); + return Result; +} + +// Visitor to check equality of values stored in variants. +// Assumes both values have the same type. +struct EqVisitor { + const void *ErasedRHSVal; // Points to the value stored in B. + + template bool operator()(const T &LHSVal) const { + const T &RHSVal = *reinterpret_cast(ErasedRHSVal); + return DenseMapInfo::eq(LHSVal, RHSVal); + } +}; + +} // namespace detail + // Provide DenseMapInfo for variants whose all alternatives have DenseMapInfo. template struct DenseMapInfo> { using Variant = std::variant; @@ -318,7 +344,17 @@ } static bool isEqual(const Variant &LHS, const Variant &RHS) { - return LHS == RHS; + if (LHS.index() != RHS.index()) return false; + if (LHS.valueless_by_exception()) return true; + // We want to dispatch to DenseMapInfo::isEqual(LHS.get(I), RHS.get(I)) + // This is surprisingly fiddly: + // - there's no get() for a runtime index (see detail::variantGetDynamic) + // - we know the types are the same, but std::visit(V, LHS, RHS) doesn't + // We erase the type held in RHS to void*, and dispatch over LHS. + return std::visit( + detail::EqVisitor{ + dyn_get(RHS, RHS.index(), std::index_sequence_for{})}, + LHS); } }; } // end namespace llvm