[clang] [Clang] Fix quadratic designated-initializer checking (PR #225573)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 22 18:57:01 PDT 2026
https://github.com/AnonMiraj created https://github.com/llvm/llvm-project/pull/225573
Every field designator rescans the record's field list to recover the field's index.
`FieldDecl::getFieldIndex()` already caches that index in the AST, so using it instead fixes the issue.
When `KnownField` is not a field of `RD` the behavior is kept as before.
| N | before | after |
| ----- | ------ | ----- |
| 10000 | 0.41s | 0.02s |
| 20000 | 1.90s | 0.03s |
| 40000 | 8.87s | 0.07s |
fixes #136568
>From ab07603afbfac0f24f48e64bfcf66ff2324a31ed Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Tue, 22 Sep 2026 02:36:26 +0300
Subject: [PATCH] [Clang] Fix quadratic designated-initializer checking
---
clang/lib/Sema/SemaInit.cpp | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 8f685feac4beba..bdb2b3fedb6421 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -363,6 +363,10 @@ class InitListChecker {
SmallVectorImpl<QualType> *AggrDeductionCandidateParamTypes = nullptr;
EmbedExpr *CurEmbed = nullptr; // Save current embed we're processing.
unsigned CurEmbedIndex = 0;
+ /// Indices of a record's unnamed bitfields, in increasing order. Usually
+ /// empty. getFieldIndex() counts them, designators don't.
+ llvm::SmallDenseMap<const RecordDecl *, SmallVector<unsigned, 0>, 2>
+ UnnamedBitFieldIndices;
NoInitExpr *getDummyInit() {
if (!DummyExpr)
@@ -3012,14 +3016,28 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
unsigned FieldIndex = NumBases;
- for (auto *FI : RD->fields()) {
- if (FI->isUnnamedBitField())
- continue;
- if (declaresSameEntity(KnownField, FI)) {
- KnownField = FI;
- break;
+ // Avoid a quadratic per-designator scan; the AST caches each field's
+ // index.
+ if (KnownField->getParent() == RD) {
+ auto [It, Inserted] = UnnamedBitFieldIndices.try_emplace(RD);
+ if (Inserted)
+ for (const FieldDecl *FI : RD->fields())
+ if (FI->isUnnamedBitField())
+ It->second.push_back(FI->getFieldIndex());
+ unsigned Index = KnownField->getFieldIndex();
+ FieldIndex +=
+ Index - (llvm::lower_bound(It->second, Index) - It->second.begin());
+ } else {
+ // A field of another record: its cached index isn't RD's numbering.
+ for (auto *FI : RD->fields()) {
+ if (FI->isUnnamedBitField())
+ continue;
+ if (declaresSameEntity(KnownField, FI)) {
+ KnownField = FI;
+ break;
+ }
+ ++FieldIndex;
}
- ++FieldIndex;
}
RecordDecl::field_iterator Field =
More information about the cfe-commits
mailing list