[clang] [Clang] Fix quadratic designated-initializer checking (PR #225573)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 26 20:52:29 PDT 2026
https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/225573
>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 1/2] [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 8f685feac4beb..bdb2b3fedb642 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 =
>From c59a6da4552f848a360541cd5875b60f56439071 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Fri, 25 Sep 2026 02:29:18 +0300
Subject: [PATCH 2/2] Move the designator field index lookup to ASTContext
---
clang/include/clang/AST/ASTContext.h | 9 +++++++++
clang/lib/AST/ASTContext.cpp | 15 +++++++++++++++
clang/lib/Sema/SemaInit.cpp | 16 +++-------------
3 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index a4ed852d36442..5ccf885b8a6e7 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -330,6 +330,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// This is lazily created. This is intentionally not serialized.
mutable llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>
ASTRecordLayouts;
+ /// Indices of a record's unnamed bitfields, in increasing order. Usually
+ /// empty. getFieldIndex() counts them, designators don't.
+ mutable llvm::DenseMap<const RecordDecl *, llvm::SmallVector<unsigned, 0>>
+ UnnamedBitFieldIndices;
mutable llvm::DenseMap<const ObjCInterfaceDecl *, const ASTRecordLayout *>
ObjCLayouts;
@@ -2875,6 +2879,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// position information.
const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const;
+ /// Returns the index of Field among RD's named fields, the numbering
+ /// designators use.
+ std::optional<unsigned> getFieldIndex(const RecordDecl *RD,
+ const FieldDecl *Field) const;
+
/// Get or compute information about the layout of the specified
/// Objective-C interface.
const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index abf0cd5e18c2b..8b6233ebdc8cd 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3236,6 +3236,21 @@ ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) const {
return getObjCLayout(D);
}
+std::optional<unsigned>
+ASTContext::getFieldIndex(const RecordDecl *RD, const FieldDecl *Field) const {
+ if (Field->getParent() != RD)
+ return std::nullopt;
+
+ // Designators skip unnamed bitfields; subtract the ones before Field.
+ 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 = Field->getFieldIndex();
+ return Index - (llvm::lower_bound(It->second, Index) - It->second.begin());
+}
+
static auto getCanonicalTemplateArguments(const ASTContext &C,
ArrayRef<TemplateArgument> Args,
bool &AnyNonCanonArgs) {
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index bdb2b3fedb642..6e1ddcb6a7cab 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -363,10 +363,6 @@ 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)
@@ -3018,15 +3014,9 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// 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());
+ if (std::optional<unsigned> SelfIndex =
+ SemaRef.Context.getFieldIndex(RD, KnownField)) {
+ FieldIndex += *SelfIndex;
} else {
// A field of another record: its cached index isn't RD's numbering.
for (auto *FI : RD->fields()) {
More information about the cfe-commits
mailing list