Author: Oleksandr Tarasiuk Date: 2026-01-30T15:17:56+02:00 New Revision: d473a87a165660bbf690ba4d030c4fda85ac67e8
URL: https://github.com/llvm/llvm-project/commit/d473a87a165660bbf690ba4d030c4fda85ac67e8 DIFF: https://github.com/llvm/llvm-project/commit/d473a87a165660bbf690ba4d030c4fda85ac67e8.diff LOG: [Clang] speed up -Wassign-enum via enumerator caching (#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. The following charts demonstrate the benchmark results before and after caching enumerator values Before <img width="640" height="480" alt="before_enum_assign" src="https://github.com/user-attachments/assets/cbc9de29-32cd-452e-84e9-383dcf334bac" /> After <img width="756" height="579" alt="after_enum_assign" src="https://github.com/user-attachments/assets/891b3839-9d70-4e60-ab21-de98ce4cca0a" /> Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaStmt.cpp clang/test/Sema/warn-outof-range-assign-enum.c Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bb40cff50b8f0..de155256999d0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -202,6 +202,8 @@ Improvements to Clang's diagnostics DanglingView(std::string s) : view(s) {} // warning: address of stack memory escapes to a field }; +- 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 7b3479bbc3677..0ba3daab764b7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3544,6 +3544,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. + llvm::DenseMap<const EnumDecl *, llvm::SmallVector<llvm::APSInt>> + 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 5ab10fdfc7b74..ba5ba80d6a0bc 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1761,30 +1761,30 @@ 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); + 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()) { + Values.push_back(EC->getInitVal()); + AdjustAPSInt(Values.back(), DstWidth, DstIsSigned); + } + + if (Values.empty()) + return; + + llvm::sort(Values); + Values.erase(llvm::unique(Values), Values.end()); } - if (EnumVals.empty()) + + if (llvm::binary_search(Values, *RHSVal)) 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
