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
