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 <[email protected]>
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 =

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

Reply via email to