https://github.com/a-tarasyuk created 
https://github.com/llvm/llvm-project/pull/176560

Fixes #176454

---

This patch addresses a performance issue in `-Wassign-enum` where enumerator 
values were repeatedly rebuilt and sorted for each assignment check, leading to 
excessive compile-time overhead for large enums.




>From 0651b94ef5e9708f16bf5eed37379abc88417c0b Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Sat, 17 Jan 2026 13:14:41 +0200
Subject: [PATCH] [Clang] speed up -Wassign-enum via enumerator caching

---
 clang/docs/ReleaseNotes.rst                   |  1 +
 clang/include/clang/Sema/Sema.h               |  4 ++
 clang/lib/Sema/SemaStmt.cpp                   | 47 ++++++++++---------
 .../test/Sema/warn-outof-range-assign-enum.c  | 13 ++++-
 4 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4139d1d80ed4a..c9e19128af74e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -105,6 +105,7 @@ Attribute Changes in Clang
 
 Improvements to Clang's diagnostics
 -----------------------------------
+- Improved `-Wassign-enum` performance by caching enum enumerator values. 
(#GH176454)
 
 Improvements to Clang's time-trace
 ----------------------------------
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 23eb954ce774c..7929f26fd92d0 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3522,6 +3522,10 @@ class Sema final : public SemaBase {
   /// attribute.
   mutable llvm::DenseMap<const EnumDecl *, llvm::APInt> FlagBitsCache;
 
+  /// A cache of enumerator values for enums checked by -Wassign-enum.
+  mutable llvm::DenseMap<const EnumDecl *, llvm::SmallVector<llvm::APSInt, 64>>
+      AssignEnumCache;
+
   /// WeakUndeclaredIdentifiers - Identifiers contained in \#pragma weak before
   /// declared. Rare. May alias another identifier, declared or undeclared.
   ///
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..18788ed4b428f 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1761,30 +1761,35 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType 
SrcType,
     return;
   }
 
-  typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
-      EnumValsTy;
-  EnumValsTy EnumVals;
-
-  // Gather all enum values, set their type and sort them,
-  // allowing easier comparison with rhs constant.
-  for (auto *EDI : ED->enumerators()) {
-    llvm::APSInt Val = EDI->getInitVal();
-    AdjustAPSInt(Val, DstWidth, DstIsSigned);
-    EnumVals.emplace_back(Val, EDI);
+  auto EnumValuesCmp = [](const llvm::APSInt &A, const llvm::APSInt &B) {
+    return A < B;
+  };
+
+  const EnumDecl *Key = ED->getCanonicalDecl();
+  auto [It, Inserted] = AssignEnumCache.try_emplace(Key);
+  auto &Values = It->second;
+
+  if (Inserted) {
+    Values.reserve(std::distance(ED->enumerator_begin(), 
ED->enumerator_end()));
+
+    for (auto *EC : ED->enumerators()) {
+      llvm::APSInt V = EC->getInitVal();
+      AdjustAPSInt(V, DstWidth, DstIsSigned);
+      Values.push_back(V);
+    }
+
+    if (Values.empty())
+      return;
+
+    llvm::sort(Values, EnumValuesCmp);
+    Values.erase(llvm::unique(Values), Values.end());
   }
-  if (EnumVals.empty())
+
+  if (llvm::binary_search(Values, *RHSVal, EnumValuesCmp))
     return;
-  llvm::stable_sort(EnumVals, CmpEnumVals);
-  EnumValsTy::iterator EIend = llvm::unique(EnumVals, EqEnumVals);
 
-  // See which values aren't in the enum.
-  EnumValsTy::const_iterator EI = EnumVals.begin();
-  while (EI != EIend && EI->first < *RHSVal)
-    EI++;
-  if (EI == EIend || EI->first != *RHSVal) {
-    Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
-        << DstType.getUnqualifiedType();
-  }
+  Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
+      << DstType.getUnqualifiedType();
 }
 
 StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc,
diff --git a/clang/test/Sema/warn-outof-range-assign-enum.c 
b/clang/test/Sema/warn-outof-range-assign-enum.c
index 23c78497b37e4..0d8a4dab114e2 100644
--- a/clang/test/Sema/warn-outof-range-assign-enum.c
+++ b/clang/test/Sema/warn-outof-range-assign-enum.c
@@ -50,6 +50,18 @@ void f(void)
   x += 1; // expected-warning {{integer constant not in range of enumerated 
type}}
 }
 
+typedef enum OutOfOrderTestEnum {
+  OO1 = 100,
+  OO2 = 50,
+  OO3 = 75,
+  OO4 = 9,
+  OO5 = 99
+} OutOfOrderTestEnum;
+
+OutOfOrderTestEnum t1 = 75;
+OutOfOrderTestEnum t2 = 9;
+OutOfOrderTestEnum t3 = 76; // expected-warning {{integer constant not in 
range of enumerated type 'OutOfOrderTestEnum'}}
+
 int main(void) {
   CCTestEnum test = 1; // expected-warning {{integer constant not in range of 
enumerated type 'CCTestEnum'}}
   test = 600; // expected-warning {{integer constant not in range of 
enumerated type 'CCTestEnum'}}
@@ -58,4 +70,3 @@ int main(void) {
   foo(4);
   foo(Two+1);
 }
-

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

Reply via email to