https://github.com/kparzysz updated 
https://github.com/llvm/llvm-project/pull/210405

>From 8b931740b452c8bb438d3ba761259f4cf6881016 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <[email protected]>
Date: Fri, 17 Jul 2026 11:01:43 -0500
Subject: [PATCH 1/2] [ADT] Make enum iterators constexpr

---
 llvm/include/llvm/ADT/Sequence.h | 142 +++++++++++++++++++------------
 1 file changed, 87 insertions(+), 55 deletions(-)

diff --git a/llvm/include/llvm/ADT/Sequence.h b/llvm/include/llvm/ADT/Sequence.h
index ae446df345ee0..b79c794526a8e 100644
--- a/llvm/include/llvm/ADT/Sequence.h
+++ b/llvm/include/llvm/ADT/Sequence.h
@@ -102,7 +102,7 @@ template <typename EnumT> struct enum_iteration_traits {
 };
 
 struct force_iteration_on_noniterable_enum_t {
-  explicit force_iteration_on_noniterable_enum_t() = default;
+  explicit constexpr force_iteration_on_noniterable_enum_t() = default;
 };
 
 inline constexpr force_iteration_on_noniterable_enum_t
@@ -111,7 +111,8 @@ inline constexpr force_iteration_on_noniterable_enum_t
 namespace detail {
 
 // Returns whether a value of type U can be represented with type T.
-template <typename T, typename U> bool canTypeFitValue(const U Value) {
+template <typename T, typename U>
+constexpr bool canTypeFitValue(const U Value) {
   const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
   const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
   const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
@@ -128,7 +129,7 @@ struct CheckedInt {
   // Integral constructor, asserts if Value cannot be represented as intmax_t.
   template <typename Integral,
             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
-  static CheckedInt from(Integral FromValue) {
+  static constexpr CheckedInt from(Integral FromValue) {
     if (!canTypeFitValue<intmax_t>(FromValue))
       assertOutOfBounds();
     CheckedInt Result;
@@ -139,24 +140,28 @@ struct CheckedInt {
   // Enum constructor, asserts if Value cannot be represented as intmax_t.
   template <typename Enum,
             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
-  static CheckedInt from(Enum FromValue) {
+  static constexpr CheckedInt from(Enum FromValue) {
     return from(llvm::to_underlying(FromValue));
   }
 
   // Equality
-  bool operator==(const CheckedInt &O) const { return Value == O.Value; }
-  bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
+  constexpr bool operator==(const CheckedInt &O) const {
+    return Value == O.Value;
+  }
+  constexpr bool operator!=(const CheckedInt &O) const {
+    return Value != O.Value;
+  }
 
-  CheckedInt operator+(intmax_t Offset) const {
-    CheckedInt Result;
-    if (AddOverflow(Value, Offset, Result.Value))
+  constexpr CheckedInt operator+(intmax_t Offset) const {
+    auto [Result, Overflow] = AddOverflow(Value, Offset);
+    if (Overflow)
       assertOutOfBounds();
-    return Result;
+    return CheckedInt::from(Result);
   }
 
-  intmax_t operator-(CheckedInt Other) const {
-    intmax_t Result;
-    if (SubOverflow(Value, Other.Value, Result))
+  constexpr intmax_t operator-(CheckedInt Other) const {
+    auto [Result, Overflow] = SubOverflow(Value, Other.Value);
+    if (Overflow)
       assertOutOfBounds();
     return Result;
   }
@@ -164,7 +169,7 @@ struct CheckedInt {
   // Convert to integral, asserts if Value cannot be represented as Integral.
   template <typename Integral,
             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
-  Integral to() const {
+  constexpr Integral to() const {
     if (!canTypeFitValue<Integral>(Value))
       assertOutOfBounds();
     return static_cast<Integral>(Value);
@@ -174,15 +179,17 @@ struct CheckedInt {
   // underlying type.
   template <typename Enum,
             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
-  Enum to() const {
+  constexpr Enum to() const {
     using type = std::underlying_type_t<Enum>;
     return Enum(to<type>());
   }
 
 private:
-  static void assertOutOfBounds() { assert(false && "Out of bounds"); }
+  [[noreturn]] static void assertOutOfBounds() {
+    assert(false && "Out of bounds");
+  }
 
-  intmax_t Value;
+  intmax_t Value = 0;
 };
 
 template <typename T, bool IsReverse> struct SafeIntIterator {
@@ -193,63 +200,85 @@ template <typename T, bool IsReverse> struct 
SafeIntIterator {
   using reference = value_type; // The iterator does not reference memory.
 
   // Construct from T.
-  explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
+  explicit constexpr SafeIntIterator(T Value)
+      : SI(CheckedInt::from<T>(Value)) {}
   // Construct from other direction.
-  SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O) : SI(O.SI) {}
+  constexpr SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O)
+      : SI(O.SI) {}
 
   // Dereference
-  reference operator*() const { return SI.to<T>(); }
+  constexpr reference operator*() const { return SI.to<T>(); }
   // Indexing
-  reference operator[](intmax_t Offset) const { return *(*this + Offset); }
+  constexpr reference operator[](intmax_t Offset) const {
+    return *(*this + Offset);
+  }
 
   // Can be compared for equivalence using the equality/inequality operators.
-  bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
-  bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
+  constexpr bool operator==(const SafeIntIterator &O) const {
+    return SI == O.SI;
+  }
+  constexpr bool operator!=(const SafeIntIterator &O) const {
+    return SI != O.SI;
+  }
   // Comparison
-  bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
-  bool operator>(const SafeIntIterator &O) const { return (*this - O) > 0; }
-  bool operator<=(const SafeIntIterator &O) const { return (*this - O) <= 0; }
-  bool operator>=(const SafeIntIterator &O) const { return (*this - O) >= 0; }
+  constexpr bool operator<(const SafeIntIterator &O) const {
+    return (*this - O) < 0;
+  }
+  constexpr bool operator>(const SafeIntIterator &O) const {
+    return (*this - O) > 0;
+  }
+  constexpr bool operator<=(const SafeIntIterator &O) const {
+    return (*this - O) <= 0;
+  }
+  constexpr bool operator>=(const SafeIntIterator &O) const {
+    return (*this - O) >= 0;
+  }
 
   // Pre Increment/Decrement
-  void operator++() { offset(1); }
-  void operator--() { offset(-1); }
+  constexpr void operator++() { offset(1); }
+  constexpr void operator--() { offset(-1); }
 
   // Post Increment/Decrement
-  SafeIntIterator operator++(int) {
+  constexpr SafeIntIterator operator++(int) {
     const auto Copy = *this;
     ++*this;
     return Copy;
   }
-  SafeIntIterator operator--(int) {
+  constexpr SafeIntIterator operator--(int) {
     const auto Copy = *this;
     --*this;
     return Copy;
   }
 
   // Compound assignment operators
-  void operator+=(intmax_t Offset) { offset(Offset); }
-  void operator-=(intmax_t Offset) { offset(-Offset); }
+  constexpr void operator+=(intmax_t Offset) { offset(Offset); }
+  constexpr void operator-=(intmax_t Offset) { offset(-Offset); }
 
   // Arithmetic
-  SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
-  SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
+  constexpr SafeIntIterator operator+(intmax_t Offset) const {
+    return add(Offset);
+  }
+  constexpr SafeIntIterator operator-(intmax_t Offset) const {
+    return add(-Offset);
+  }
 
   // Difference
-  intmax_t operator-(const SafeIntIterator &O) const {
+  constexpr intmax_t operator-(const SafeIntIterator &O) const {
     return IsReverse ? O.SI - SI : SI - O.SI;
   }
 
 private:
-  SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
+  constexpr SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
 
-  static intmax_t getOffset(intmax_t Offset) {
+  static constexpr intmax_t getOffset(intmax_t Offset) {
     return IsReverse ? -Offset : Offset;
   }
 
-  CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
+  constexpr CheckedInt add(intmax_t Offset) const {
+    return SI + getOffset(Offset);
+  }
 
-  void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
+  constexpr void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
 
   CheckedInt SI;
 
@@ -270,21 +299,23 @@ template <typename T> struct iota_range {
   using difference_type = intmax_t;
   using size_type = std::size_t;
 
-  explicit iota_range(T Begin, T End, bool Inclusive)
+  explicit constexpr iota_range(T Begin, T End, bool Inclusive)
       : BeginValue(Begin), PastEndValue(End) {
     assert(Begin <= End && "Begin must be less or equal to End.");
     if (Inclusive)
       ++PastEndValue;
   }
 
-  size_t size() const { return PastEndValue - BeginValue; }
-  bool empty() const { return BeginValue == PastEndValue; }
+  constexpr size_t size() const { return PastEndValue - BeginValue; }
+  constexpr bool empty() const { return BeginValue == PastEndValue; }
 
-  auto begin() const { return const_iterator(BeginValue); }
-  auto end() const { return const_iterator(PastEndValue); }
+  constexpr auto begin() const { return const_iterator(BeginValue); }
+  constexpr auto end() const { return const_iterator(PastEndValue); }
 
-  auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
-  auto rend() const { return const_reverse_iterator(BeginValue - 1); }
+  constexpr auto rbegin() const {
+    return const_reverse_iterator(PastEndValue - 1);
+  }
+  constexpr auto rend() const { return const_reverse_iterator(BeginValue - 1); 
}
 
 private:
   static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
@@ -302,7 +333,7 @@ template <typename T> struct iota_range {
 /// iteration).
 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
                                                   !std::is_enum<T>::value>>
-auto seq(T Begin, T End) {
+constexpr auto seq(T Begin, T End) {
   return iota_range<T>(Begin, End, false);
 }
 
@@ -312,7 +343,7 @@ auto seq(T Begin, T End) {
 /// iteration).
 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
                                                   !std::is_enum<T>::value>>
-auto seq(T Size) {
+constexpr auto seq(T Size) {
   return seq<T>(0, Size);
 }
 
@@ -322,7 +353,7 @@ auto seq(T Size) {
 /// iteration).
 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
                                                   !std::is_enum<T>::value>>
-auto seq_inclusive(T Begin, T End) {
+constexpr auto seq_inclusive(T Begin, T End) {
   return iota_range<T>(Begin, End, true);
 }
 
@@ -334,7 +365,7 @@ auto seq_inclusive(T Begin, T End) {
 /// iteration).
 template <typename EnumT,
           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
-auto enum_seq(EnumT Begin, EnumT End) {
+constexpr auto enum_seq(EnumT Begin, EnumT End) {
   static_assert(enum_iteration_traits<EnumT>::is_iterable,
                 "Enum type is not marked as iterable.");
   return iota_range<EnumT>(Begin, End, false);
@@ -349,7 +380,8 @@ auto enum_seq(EnumT Begin, EnumT End) {
 /// iteration).
 template <typename EnumT,
           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
-auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
+constexpr auto enum_seq(EnumT Begin, EnumT End,
+                        force_iteration_on_noniterable_enum_t) {
   return iota_range<EnumT>(Begin, End, false);
 }
 
@@ -361,7 +393,7 @@ auto enum_seq(EnumT Begin, EnumT End, 
force_iteration_on_noniterable_enum_t) {
 /// iteration).
 template <typename EnumT,
           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
-auto enum_seq_inclusive(EnumT Begin, EnumT End) {
+constexpr auto enum_seq_inclusive(EnumT Begin, EnumT End) {
   static_assert(enum_iteration_traits<EnumT>::is_iterable,
                 "Enum type is not marked as iterable.");
   return iota_range<EnumT>(Begin, End, true);
@@ -376,8 +408,8 @@ auto enum_seq_inclusive(EnumT Begin, EnumT End) {
 /// iteration).
 template <typename EnumT,
           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
-auto enum_seq_inclusive(EnumT Begin, EnumT End,
-                        force_iteration_on_noniterable_enum_t) {
+constexpr auto enum_seq_inclusive(EnumT Begin, EnumT End,
+                                  force_iteration_on_noniterable_enum_t) {
   return iota_range<EnumT>(Begin, End, true);
 }
 

>From bb45367afd2a2e08317c5e18523dfe9c30afa90c Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <[email protected]>
Date: Fri, 17 Jul 2026 17:55:41 -0500
Subject: [PATCH 2/2] Add constexpr checks

---
 llvm/unittests/ADT/SequenceTest.cpp | 171 +++++++++++++++++++++++-----
 1 file changed, 141 insertions(+), 30 deletions(-)

diff --git a/llvm/unittests/ADT/SequenceTest.cpp 
b/llvm/unittests/ADT/SequenceTest.cpp
index ab50ad0bb5606..28ad26ee46379 100644
--- a/llvm/unittests/ADT/SequenceTest.cpp
+++ b/llvm/unittests/ADT/SequenceTest.cpp
@@ -25,6 +25,17 @@ namespace {
 using detail::canTypeFitValue;
 using detail::CheckedInt;
 
+namespace elem {
+template <typename Elem, Elem... Values, typename Range>
+constexpr bool ElementsAre(Range &&R) {
+  if (std::distance(R.begin(), R.end()) != sizeof...(Values))
+    return false;
+
+  int Idx = 0;
+  return ((*(R.begin() + (Idx++)) == Values) && ...);
+}
+} // namespace elem
+
 using IntegralTypes = testing::Types<uint8_t,   // 0
                                      uint16_t,  // 1
                                      uint32_t,  // 2
@@ -41,34 +52,50 @@ template <class T> class StrongIntTest : public 
testing::Test {};
 TYPED_TEST_SUITE(StrongIntTest, IntegralTypes, );
 TYPED_TEST(StrongIntTest, Operations) {
   using T = TypeParam;
-  auto Max = std::numeric_limits<T>::max();
-  auto Min = std::numeric_limits<T>::min();
+  constexpr auto Max = std::numeric_limits<T>::max();
+  constexpr auto Min = std::numeric_limits<T>::min();
 
   // We bail out for types that are not entirely representable within intmax_t.
-  if (!canTypeFitValue<intmax_t>(Max) || !canTypeFitValue<intmax_t>(Min))
-    return;
-
-  // All representable values convert back and forth.
-  EXPECT_EQ(CheckedInt::from(Min).template to<T>(), Min);
-  EXPECT_EQ(CheckedInt::from(Max).template to<T>(), Max);
-
-  // Addition -2, -1, 0, 1, 2.
-  const T Expected = Max / 2;
-  const CheckedInt Actual = CheckedInt::from(Expected);
-  EXPECT_EQ((Actual + -2).template to<T>(), Expected - 2);
-  EXPECT_EQ((Actual + -1).template to<T>(), Expected - 1);
-  EXPECT_EQ((Actual + 0).template to<T>(), Expected);
-  EXPECT_EQ((Actual + 1).template to<T>(), Expected + 1);
-  EXPECT_EQ((Actual + 2).template to<T>(), Expected + 2);
-
-  // EQ/NEQ
-  EXPECT_EQ(Actual, Actual);
-  EXPECT_NE(Actual, Actual + 1);
-
-  // Difference
-  EXPECT_EQ(Actual - Actual, 0);
-  EXPECT_EQ((Actual + 1) - Actual, 1);
-  EXPECT_EQ(Actual - (Actual + 2), -2);
+  if constexpr (canTypeFitValue<intmax_t>(Max) &&
+                canTypeFitValue<intmax_t>(Min)) {
+    // All representable values convert back and forth.
+    EXPECT_EQ(CheckedInt::from(Min).template to<T>(), Min);
+    EXPECT_EQ(CheckedInt::from(Max).template to<T>(), Max);
+
+    static_assert(CheckedInt::from(Min).template to<T>() == Min);
+    static_assert(CheckedInt::from(Max).template to<T>() == Max);
+
+    // Addition -2, -1, 0, 1, 2.
+    constexpr T Expected = Max / 2;
+    constexpr CheckedInt Actual = CheckedInt::from(Expected);
+    EXPECT_EQ((Actual + -2).template to<T>(), Expected - 2);
+    EXPECT_EQ((Actual + -1).template to<T>(), Expected - 1);
+    EXPECT_EQ((Actual + 0).template to<T>(), Expected);
+    EXPECT_EQ((Actual + 1).template to<T>(), Expected + 1);
+    EXPECT_EQ((Actual + 2).template to<T>(), Expected + 2);
+
+    static_assert((Actual + -2).template to<T>() == Expected - 2);
+    static_assert((Actual + -1).template to<T>() == Expected - 1);
+    static_assert((Actual + 0).template to<T>() == Expected);
+    static_assert((Actual + 1).template to<T>() == Expected + 1);
+    static_assert((Actual + 2).template to<T>() == Expected + 2);
+
+    // EQ/NEQ
+    EXPECT_EQ(Actual, Actual);
+    EXPECT_NE(Actual, Actual + 1);
+
+    static_assert(Actual == Actual);
+    static_assert(Actual != Actual + 1);
+
+    // Difference
+    EXPECT_EQ(Actual - Actual, 0);
+    EXPECT_EQ((Actual + 1) - Actual, 1);
+    EXPECT_EQ(Actual - (Actual + 2), -2);
+
+    static_assert(Actual - Actual == 0);
+    static_assert((Actual + 1) - Actual == 1);
+    static_assert(Actual - (Actual + 2) == -2);
+  }
 }
 
 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
@@ -88,6 +115,9 @@ TEST(StrongIntDeathTest, OutOfBounds) {
 #endif
 
 TEST(SafeIntIteratorTest, Operations) {
+  constexpr detail::SafeIntIterator<int, false> CForward(0);
+  constexpr detail::SafeIntIterator<int, true> CReverse(0);
+
   detail::SafeIntIterator<int, false> Forward(0);
   detail::SafeIntIterator<int, true> Reverse(0);
 
@@ -114,16 +144,38 @@ TEST(SafeIntIteratorTest, Operations) {
   EXPECT_GE(Reverse, Reverse);
   EXPECT_GE(Reverse + 1, Reverse);
 
+  static_assert(CForward == CForward);
+  static_assert(CForward - 1 < CForward);
+  static_assert(CForward <= CForward);
+  static_assert(CForward - 1 <= CForward);
+  static_assert(CForward + 1 > CForward);
+  static_assert(CForward >= CForward);
+  static_assert(CForward + 1 >= CForward);
+
+  static_assert(CReverse == CReverse);
+  static_assert(CReverse - 1 < CReverse);
+  static_assert(CReverse <= CReverse);
+  static_assert(CReverse - 1 <= CReverse);
+  static_assert(CReverse + 1 > CReverse);
+  static_assert(CReverse >= CReverse);
+  static_assert(CReverse + 1 >= CReverse);
+
   // Dereference
   SetToZero();
   EXPECT_EQ(*Forward, 0);
   EXPECT_EQ(*Reverse, 0);
 
+  static_assert(*CForward == 0);
+  static_assert(*CReverse == 0);
+
   // Indexing
   SetToZero();
   EXPECT_EQ(Forward[2], 2);
   EXPECT_EQ(Reverse[2], -2);
 
+  static_assert(CForward[2] == 2);
+  static_assert(CReverse[2] == -2);
+
   // Pre-increment
   SetToZero();
   ++Forward;
@@ -168,9 +220,13 @@ TEST(SafeIntIteratorTest, Operations) {
   SetToZero();
   EXPECT_EQ(*(Forward + 3), 3);
   EXPECT_EQ(*(Reverse + 3), -3);
+  static_assert(*(CForward + 3) == 3);
+  static_assert(*(CReverse + 3) == -3);
   SetToZero();
   EXPECT_EQ(*(Forward - 4), -4);
   EXPECT_EQ(*(Reverse - 4), 4);
+  static_assert(*(CForward - 4) == -4);
+  static_assert(*(CReverse - 4) == 4);
 
   // Difference
   SetToZero();
@@ -180,33 +236,53 @@ TEST(SafeIntIteratorTest, Operations) {
   EXPECT_EQ(Forward - (Forward + 1), -1);
   EXPECT_EQ((Reverse + 1) - Reverse, 1);
   EXPECT_EQ(Reverse - (Reverse + 1), -1);
+
+  static_assert(CForward - CForward == 0);
+  static_assert(CReverse - CReverse == 0);
+  static_assert((CForward + 1) - CForward == 1);
+  static_assert(CForward - (CForward + 1) == -1);
+  static_assert((CReverse + 1) - CReverse == 1);
+  static_assert(CReverse - (CReverse + 1) == -1);
 }
 
 TEST(SequenceTest, Iteration) {
   EXPECT_THAT(seq(5), ElementsAre(0, 1, 2, 3, 4));
+  static_assert(elem::ElementsAre<int, 0, 1, 2, 3, 4>(seq(5)));
 
   EXPECT_THAT(seq(-4, 5), ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4));
+  static_assert(
+      elem::ElementsAre<int, -4, -3, -2, -1, 0, 1, 2, 3, 4>(seq(-4, 5)));
   EXPECT_THAT(reverse(seq(-4, 5)), ElementsAre(4, 3, 2, 1, 0, -1, -2, -3, -4));
 
   EXPECT_THAT(seq_inclusive(-4, 5),
               ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4, 5));
+  static_assert(elem::ElementsAre<int, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5>(
+      seq_inclusive(-4, 5)));
   EXPECT_THAT(reverse(seq_inclusive(-4, 5)),
               ElementsAre(5, 4, 3, 2, 1, 0, -1, -2, -3, -4));
+  // reverse is not constexpr
 }
 
 TEST(SequenceTest, Distance) {
-  const auto Forward = seq(0, 10);
+  constexpr auto Forward = seq(0, 10);
   EXPECT_EQ(std::distance(Forward.begin(), Forward.end()), 10);
   EXPECT_EQ(std::distance(Forward.rbegin(), Forward.rend()), 10);
+  static_assert(std::distance(Forward.begin(), Forward.end()) == 10);
+  static_assert(std::distance(Forward.rbegin(), Forward.rend()) == 10);
 }
 
 TEST(SequenceTest, Dereference) {
-  const auto Forward = seq(0, 10).begin();
+  constexpr auto Forward = seq(0, 10).begin();
   EXPECT_EQ(Forward[0], 0);
   EXPECT_EQ(Forward[2], 2);
-  const auto Backward = seq(0, 10).rbegin();
+  static_assert(Forward[0] == 0);
+  static_assert(Forward[2] == 2);
+
+  constexpr auto Backward = seq(0, 10).rbegin();
   EXPECT_EQ(Backward[0], 9);
   EXPECT_EQ(Backward[2], 7);
+  static_assert(Backward[0] == 9);
+  static_assert(Backward[2] == 7);
 }
 
 enum UntypedEnum { A = 3 };
@@ -225,7 +301,7 @@ struct S {
   friend struct llvm::enum_iteration_traits<NestedEnum3>;
 
 public:
-  static auto getNestedEnum3() { return NestedEnum3::F; }
+  static constexpr auto getNestedEnum3() { return NestedEnum3::F; }
 };
 
 } // namespace
@@ -261,42 +337,77 @@ TEST(StrongIntTest, Enums) {
   EXPECT_EQ(CheckedInt::from(B).to<TypedEnum>(), B);
   EXPECT_EQ(CheckedInt::from(X::ScopedEnum::C).to<X::ScopedEnum>(),
             X::ScopedEnum::C);
+
+  static_assert(CheckedInt::from(A).to<UntypedEnum>() == A);
+  static_assert(CheckedInt::from(B).to<TypedEnum>() == B);
+  static_assert(CheckedInt::from(X::ScopedEnum::C).to<X::ScopedEnum>() ==
+                X::ScopedEnum::C);
 }
 
 TEST(SequenceTest, IterableEnums) {
   EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A), IsEmpty());
+  static_assert(
+      elem::ElementsAre<UntypedEnum>(enum_seq(UntypedEnum::A, 
UntypedEnum::A)));
+
   EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A),
               ElementsAre(UntypedEnum::A));
+  static_assert(elem::ElementsAre<UntypedEnum, UntypedEnum::A>(
+      enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A)));
 
   EXPECT_THAT(enum_seq(TypedEnum::B, TypedEnum::B), IsEmpty());
+  static_assert(
+      elem::ElementsAre<TypedEnum>(enum_seq(TypedEnum::B, TypedEnum::B)));
   EXPECT_THAT(enum_seq_inclusive(TypedEnum::B, TypedEnum::B),
               ElementsAre(TypedEnum::B));
+  static_assert(elem::ElementsAre<TypedEnum, TypedEnum::B>(
+      enum_seq_inclusive(TypedEnum::B, TypedEnum::B)));
 
   EXPECT_THAT(enum_seq(X::ScopedEnum::C, X::ScopedEnum::C), IsEmpty());
+  static_assert(
+      elem::ElementsAre<X::ScopedEnum>(enum_seq(X::ScopedEnum::C, 
X::ScopedEnum::C)));
   EXPECT_THAT(enum_seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C),
               ElementsAre(X::ScopedEnum::C));
+  static_assert(elem::ElementsAre<X::ScopedEnum, X::ScopedEnum::C>(
+      enum_seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C)));
 
   EXPECT_THAT(enum_seq_inclusive(S::NestedEnum::D, S::NestedEnum::D),
               ElementsAre(S::NestedEnum::D));
+  static_assert(elem::ElementsAre<S::NestedEnum, S::NestedEnum::D>(
+      enum_seq_inclusive(S::NestedEnum::D, S::NestedEnum::D)));
   EXPECT_THAT(enum_seq_inclusive(S::getNestedEnum3(), S::getNestedEnum3()),
               ElementsAre(S::getNestedEnum3()));
+  static_assert(
+      elem::ElementsAre<decltype(S::getNestedEnum3()), S::getNestedEnum3()>(
+          enum_seq_inclusive(S::getNestedEnum3(), S::getNestedEnum3())));
 }
 
 TEST(SequenceTest, NonIterableEnums) {
   EXPECT_THAT(enum_seq(S::NestedEnum2::E, S::NestedEnum2::E,
                        force_iteration_on_noniterable_enum),
               IsEmpty());
+  static_assert(elem::ElementsAre<S::NestedEnum2>(
+      enum_seq(S::NestedEnum2::E, S::NestedEnum2::E,
+               force_iteration_on_noniterable_enum)));
+
   EXPECT_THAT(enum_seq_inclusive(S::NestedEnum2::E, S::NestedEnum2::E,
                                  force_iteration_on_noniterable_enum),
               ElementsAre(S::NestedEnum2::E));
+  static_assert(elem::ElementsAre<S::NestedEnum2, S::NestedEnum2::E>(
+      enum_seq_inclusive(S::NestedEnum2::E, S::NestedEnum2::E,
+                         force_iteration_on_noniterable_enum)));
 
   // Check that this also works with enums marked as iterable.
   EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A,
                        force_iteration_on_noniterable_enum),
               IsEmpty());
+  static_assert(elem::ElementsAre<UntypedEnum>(enum_seq(
+      UntypedEnum::A, UntypedEnum::A, force_iteration_on_noniterable_enum)));
   EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A,
                                  force_iteration_on_noniterable_enum),
               ElementsAre(UntypedEnum::A));
+  static_assert(elem::ElementsAre<UntypedEnum, UntypedEnum::A>(
+      enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A,
+                         force_iteration_on_noniterable_enum)));
 }
 
 // Reproducer for https://github.com/llvm/llvm-project/issues/61122

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to