[clang] [clang] Add FixItHint for designated init order (PR #173136)
Mythreya Kuricheti via cfe-commits
cfe-commits at lists.llvm.org
Fri Dec 19 22:38:17 PST 2025
https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/173136
>From 4b5b1dcd3cfd26b0192905f8679ec29967e36f27 Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Thu, 18 Dec 2025 23:21:50 -0800
Subject: [PATCH 1/5] [clang] Add FixItHint for designated init order
---
clang/lib/Sema/SemaInit.cpp | 59 ++++++++++++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index cc6ddf568d346..3eb648506e758 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -31,8 +31,10 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaObjC.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
@@ -3092,6 +3094,60 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
PrevField = *FI;
}
+ const auto GenerateDesignatedInitReorderingFixit = [&]() -> FixItHint {
+ struct ReorderInfo {
+ int Pos{};
+ const Expr *InitExpr{};
+ };
+
+ llvm::SmallDenseMap<IdentifierInfo *, int> MemberNameInx{};
+ llvm::SmallVector<ReorderInfo, 16> ReorderedInitExprs{};
+
+ const auto *CxxRecord =
+ IList->getSemanticForm()->getType()->getAsCXXRecordDecl();
+
+ for (const auto &Field : CxxRecord->fields()) {
+ MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex();
+ }
+
+ for (const auto *Init : IList->inits()) {
+ if (const auto *DI = dyn_cast_if_present<DesignatedInitExpr>(Init)) {
+ // We expect only one Designator
+ if (DI->size() != 1)
+ return {};
+
+ const auto *const FieldName = DI->getDesignator(0)->getFieldName();
+ // In case we have an unknown initializer in the source, not in the
+ // record
+ if (MemberNameInx.contains(FieldName))
+ ReorderedInitExprs.emplace_back(
+ ReorderInfo{MemberNameInx.at(FieldName), Init});
+ }
+ }
+
+ llvm::sort(ReorderedInitExprs,
+ [](const auto &A, const auto &B) { return A.Pos < B.Pos; });
+
+ // generate replacement
+ llvm::SmallString<128> FixedInitList{};
+ SourceManager &SM = SemaRef.getSourceManager();
+ const LangOptions &LangOpts = SemaRef.getLangOpts();
+
+ FixedInitList += "{";
+ for (const auto &Item : ReorderedInitExprs) {
+ CharSourceRange CharRange =
+ CharSourceRange::getTokenRange(Item.InitExpr->getSourceRange());
+ const auto InitText =
+ Lexer::getSourceText(CharRange, SM, LangOpts) + ", ";
+ FixedInitList += InitText.str();
+ }
+ FixedInitList.pop_back_n(2); // remove trailing comma
+ FixedInitList += "}";
+
+ return FixItHint::CreateReplacement(IList->getSourceRange(),
+ FixedInitList);
+ };
+
if (PrevField &&
PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
SemaRef.Diag(DIE->getInit()->getBeginLoc(),
@@ -3101,9 +3157,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
unsigned OldIndex = StructuredIndex - 1;
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
+ auto ReorderFixit = GenerateDesignatedInitReorderingFixit();
SemaRef.Diag(PrevInit->getBeginLoc(),
diag::note_previous_field_init)
- << PrevField << PrevInit->getSourceRange();
+ << PrevField << PrevInit->getSourceRange() << ReorderFixit;
}
}
}
>From 69981c7cb03f5f0445eb3235643d029822d90f57 Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Thu, 18 Dec 2025 23:32:09 -0800
Subject: [PATCH 2/5] Replace exprs instead of regenerating everything
---
clang/lib/Sema/SemaInit.cpp | 103 ++++++++++++++++++------------------
1 file changed, 52 insertions(+), 51 deletions(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3eb648506e758..46ca85bfa37a5 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3094,59 +3094,60 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
PrevField = *FI;
}
- const auto GenerateDesignatedInitReorderingFixit = [&]() -> FixItHint {
- struct ReorderInfo {
- int Pos{};
- const Expr *InitExpr{};
- };
+ const auto GenerateDesignatedInitReorderingFixit =
+ [&](SemaBase::SemaDiagnosticBuilder &Diags) {
+ struct ReorderInfo {
+ int Pos{};
+ const Expr *InitExpr{};
+ };
- llvm::SmallDenseMap<IdentifierInfo *, int> MemberNameInx{};
- llvm::SmallVector<ReorderInfo, 16> ReorderedInitExprs{};
+ llvm::SmallDenseMap<IdentifierInfo *, int> MemberNameInx{};
+ llvm::SmallVector<ReorderInfo, 16> ReorderedInitExprs{};
- const auto *CxxRecord =
- IList->getSemanticForm()->getType()->getAsCXXRecordDecl();
+ const auto *CxxRecord =
+ IList->getSemanticForm()->getType()->getAsCXXRecordDecl();
- for (const auto &Field : CxxRecord->fields()) {
- MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex();
- }
+ for (const auto &Field : CxxRecord->fields()) {
+ MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex();
+ }
- for (const auto *Init : IList->inits()) {
- if (const auto *DI = dyn_cast_if_present<DesignatedInitExpr>(Init)) {
- // We expect only one Designator
- if (DI->size() != 1)
- return {};
-
- const auto *const FieldName = DI->getDesignator(0)->getFieldName();
- // In case we have an unknown initializer in the source, not in the
- // record
- if (MemberNameInx.contains(FieldName))
- ReorderedInitExprs.emplace_back(
- ReorderInfo{MemberNameInx.at(FieldName), Init});
- }
- }
+ for (const auto *Init : IList->inits()) {
+ if (const auto *DI =
+ dyn_cast_if_present<DesignatedInitExpr>(Init)) {
+ // We expect only one Designator
+ if (DI->size() != 1)
+ return;
+
+ const auto *const FieldName =
+ DI->getDesignator(0)->getFieldName();
+ // In case we have an unknown initializer in the source, not in
+ // the record
+ if (MemberNameInx.contains(FieldName))
+ ReorderedInitExprs.emplace_back(
+ ReorderInfo{MemberNameInx.at(FieldName), Init});
+ }
+ }
- llvm::sort(ReorderedInitExprs,
- [](const auto &A, const auto &B) { return A.Pos < B.Pos; });
-
- // generate replacement
- llvm::SmallString<128> FixedInitList{};
- SourceManager &SM = SemaRef.getSourceManager();
- const LangOptions &LangOpts = SemaRef.getLangOpts();
-
- FixedInitList += "{";
- for (const auto &Item : ReorderedInitExprs) {
- CharSourceRange CharRange =
- CharSourceRange::getTokenRange(Item.InitExpr->getSourceRange());
- const auto InitText =
- Lexer::getSourceText(CharRange, SM, LangOpts) + ", ";
- FixedInitList += InitText.str();
- }
- FixedInitList.pop_back_n(2); // remove trailing comma
- FixedInitList += "}";
+ llvm::sort(ReorderedInitExprs, [](const auto &A, const auto &B) {
+ return A.Pos < B.Pos;
+ });
+
+ llvm::SmallString<128> FixedInitList{};
+ SourceManager &SM = SemaRef.getSourceManager();
+ const LangOptions &LangOpts = SemaRef.getLangOpts();
- return FixItHint::CreateReplacement(IList->getSourceRange(),
- FixedInitList);
- };
+ // loop over each existing expression and apply replacement
+ for (const auto &[OrigExpr, Repl] :
+ llvm::zip(IList->inits(), ReorderedInitExprs)) {
+ CharSourceRange CharRange = CharSourceRange::getTokenRange(
+ Repl.InitExpr->getSourceRange());
+ const auto InitText =
+ Lexer::getSourceText(CharRange, SM, LangOpts);
+
+ Diags << FixItHint::CreateReplacement(OrigExpr->getSourceRange(),
+ InitText.str());
+ }
+ };
if (PrevField &&
PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
@@ -3157,10 +3158,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
unsigned OldIndex = StructuredIndex - 1;
if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
- auto ReorderFixit = GenerateDesignatedInitReorderingFixit();
- SemaRef.Diag(PrevInit->getBeginLoc(),
- diag::note_previous_field_init)
- << PrevField << PrevInit->getSourceRange() << ReorderFixit;
+ auto Diags = SemaRef.Diag(PrevInit->getBeginLoc(),
+ diag::note_previous_field_init)
+ << PrevField << PrevInit->getSourceRange();
+ GenerateDesignatedInitReorderingFixit(Diags);
}
}
}
>From 0e34b77dcb06899dd29c17eaad4a32f24cbec60b Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Fri, 19 Dec 2025 02:21:22 -0800
Subject: [PATCH 3/5] fix reordering in derived records, add tests
---
clang/lib/Sema/SemaInit.cpp | 8 ++-
.../SemaCXX/cxx2a-initializer-aggregates.cpp | 58 ++++++++++++++++++-
2 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 46ca85bfa37a5..6decf0d809153 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -3136,9 +3136,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
SourceManager &SM = SemaRef.getSourceManager();
const LangOptions &LangOpts = SemaRef.getLangOpts();
- // loop over each existing expression and apply replacement
+ // In a derived Record, first n base-classes are initialized first.
+ // They do not use designated init, so skip them
+ const auto IListInits =
+ IList->inits().drop_front(CxxRecord->getNumBases());
+ // loop over each existing expressions and apply replacement
for (const auto &[OrigExpr, Repl] :
- llvm::zip(IList->inits(), ReorderedInitExprs)) {
+ llvm::zip(IListInits, ReorderedInitExprs)) {
CharSourceRange CharRange = CharSourceRange::getTokenRange(
Repl.InitExpr->getSourceRange());
const auto InitText =
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index 1e9c5fa082d07..caadc84cf2e27 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing,wmissing-designated -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-missing-designated-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
-
+// RUN: %clang_cc1 -std=c++20 -Wreorder-init-list -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
namespace class_with_ctor {
struct A { // cxx20-note 6{{candidate}}
@@ -38,6 +38,8 @@ A a1 = {
.y = 1, // reorder-note {{previous initialization for field 'y' is here}}
.x = 2 // reorder-error {{ISO C++ requires field designators to be specified in declaration order; field 'y' will be initialized after field 'x'}}
};
+// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".x = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".y = 1"
int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}}
B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}}
A a2 = {
@@ -71,6 +73,12 @@ C c = {
.x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
.x = 1, // override-error {{overrides prior initialization}}
};
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
struct Foo { int a, b; };
@@ -118,6 +126,8 @@ namespace overload_resolution {
void i() {
h({.x = 1, .y = 2});
h({.y = 1, .x = 2}); // reorder-error {{declaration order}} reorder-note {{previous}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:14}:".x = 2"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:".y = 1"
h({.x = 1}); // expected-error {{ambiguous}}
}
@@ -228,6 +238,16 @@ struct : public A, public B {
.a = 1, // reorder-error {{field 'b' will be initialized after field 'a'}}
};
}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-17]]:4-[[@LINE-17]]:8}:".x=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-15]]:4-[[@LINE-15]]:8}:".y=1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".z=0"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".a=4"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".b=3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:5-[[@LINE-14]]:11}:".a = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-13]]:5-[[@LINE-13]]:11}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".c = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".d = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".e = 1"
namespace GH63759 {
struct C {
@@ -248,3 +268,39 @@ void foo() {
//
}
}
+
+namespace reorder_derived {
+struct col {
+ int r;
+ int g;
+ int b;
+};
+
+struct point {
+ float x;
+ float y;
+ float z;
+};
+
+struct lols : public col, public point {
+ int z2;
+ int z1;
+};
+
+void fosas() {
+ lols a {
+ {.b = 1, .g = 2, .r = 3},
+ { .z = 1, .y=2, .x = 3 },
+ .z1 = 1,
+ .z2 = 2,
+ };
+}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:6-[[@LINE-6]]:12}:".r = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:14-[[@LINE-7]]:20}:".g = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:22-[[@LINE-8]]:28}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:15-[[@LINE-8]]:19}:".y=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:28}:".z = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:7-[[@LINE-10]]:13}:".x = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z2 = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z1 = 1"
+} // namespace reorder_derived
>From 71a65a33fba52f124f475ce5ecda4798d947f4cf Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Fri, 19 Dec 2025 02:21:22 -0800
Subject: [PATCH 4/5] simplify tests
---
.../cxx20-designated-initializer-fixits.cpp | 105 ++++++++++++++++++
.../SemaCXX/cxx2a-initializer-aggregates.cpp | 58 +---------
2 files changed, 106 insertions(+), 57 deletions(-)
create mode 100644 clang/test/SemaCXX/cxx20-designated-initializer-fixits.cpp
diff --git a/clang/test/SemaCXX/cxx20-designated-initializer-fixits.cpp b/clang/test/SemaCXX/cxx20-designated-initializer-fixits.cpp
new file mode 100644
index 0000000000000..7dfdd62df292f
--- /dev/null
+++ b/clang/test/SemaCXX/cxx20-designated-initializer-fixits.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -std=c++20 %s -Wreorder-init-list -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
+
+// These tests are from clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+struct C { int :0, x, :0, y, :0; };
+C c = {
+ .x = 1,
+ .x = 1,
+ .y = 1,
+ .y = 1,
+ .x = 1,
+ .x = 1,
+};
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
+
+namespace GH63605 {
+struct A {
+ unsigned x;
+ unsigned y;
+ unsigned z;
+};
+
+struct B {
+ unsigned a;
+ unsigned b;
+};
+
+struct : public A, public B {
+ unsigned : 2;
+ unsigned a : 6;
+ unsigned : 1;
+ unsigned b : 6;
+ unsigned : 2;
+ unsigned c : 6;
+ unsigned d : 1;
+ unsigned e : 2;
+} data = {
+ {.z=0,
+
+
+ .y=1,
+
+ .x=2},
+ {.b=3,
+ .a=4},
+ .e = 1,
+
+ .d = 1,
+
+ .c = 1,
+ .b = 1,
+ .a = 1,
+};
+}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-17]]:4-[[@LINE-17]]:8}:".x=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-15]]:4-[[@LINE-15]]:8}:".y=1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".z=0"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".a=4"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".b=3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:5-[[@LINE-14]]:11}:".a = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-13]]:5-[[@LINE-13]]:11}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".c = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".d = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".e = 1"
+// END tests from clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+
+namespace reorder_derived {
+struct col {
+ int r;
+ int g;
+ int b;
+};
+
+struct point {
+ float x;
+ float y;
+ float z;
+};
+
+struct derived : public col, public point {
+ int z2;
+ int z1;
+};
+
+void test() {
+ derived a {
+ {.b = 1, .g = 2, .r = 3},
+ { .z = 1, .y=2, .x = 3 },
+ .z1 = 1,
+ .z2 = 2,
+ };
+}
+// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:6-[[@LINE-6]]:12}:".r = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:14-[[@LINE-7]]:20}:".g = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:22-[[@LINE-8]]:28}:".b = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:15-[[@LINE-8]]:19}:".y=2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:28}:".z = 1"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:7-[[@LINE-10]]:13}:".x = 3"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z2 = 2"
+// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z1 = 1"
+} // namespace reorder_derived
diff --git a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
index caadc84cf2e27..1e9c5fa082d07 100644
--- a/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
+++ b/clang/test/SemaCXX/cxx2a-initializer-aggregates.cpp
@@ -6,7 +6,7 @@
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing,wmissing-designated -Wmissing-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
// RUN: %clang_cc1 -std=c++20 %s -verify=cxx20,expected,wmissing -Wmissing-field-initializers -Wno-missing-designated-field-initializers -Wno-c99-designator -Wno-reorder-init-list -Wno-initializer-overrides
-// RUN: %clang_cc1 -std=c++20 -Wreorder-init-list -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
namespace class_with_ctor {
struct A { // cxx20-note 6{{candidate}}
@@ -38,8 +38,6 @@ A a1 = {
.y = 1, // reorder-note {{previous initialization for field 'y' is here}}
.x = 2 // reorder-error {{ISO C++ requires field designators to be specified in declaration order; field 'y' will be initialized after field 'x'}}
};
-// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".x = 2"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:3-[[@LINE-3]]:9}:".y = 1"
int arr[3] = {[1] = 5}; // pedantic-error {{array designators are a C99 extension}}
B b = {.a.x = 0}; // pedantic-error {{nested designators are a C99 extension}}
A a2 = {
@@ -73,12 +71,6 @@ C c = {
.x = 1, // reorder-error {{declaration order}} override-error {{overrides prior initialization}} override-note {{previous}}
.x = 1, // override-error {{overrides prior initialization}}
};
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".x = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:3-[[@LINE-7]]:9}:".y = 1"
struct Foo { int a, b; };
@@ -126,8 +118,6 @@ namespace overload_resolution {
void i() {
h({.x = 1, .y = 2});
h({.y = 1, .x = 2}); // reorder-error {{declaration order}} reorder-note {{previous}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:8-[[@LINE-1]]:14}:".x = 2"
- // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:".y = 1"
h({.x = 1}); // expected-error {{ambiguous}}
}
@@ -238,16 +228,6 @@ struct : public A, public B {
.a = 1, // reorder-error {{field 'b' will be initialized after field 'a'}}
};
}
-// CHECK: fix-it:"{{.*}}":{[[@LINE-17]]:4-[[@LINE-17]]:8}:".x=2"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-15]]:4-[[@LINE-15]]:8}:".y=1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".z=0"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".a=4"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:4-[[@LINE-14]]:8}:".b=3"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-14]]:5-[[@LINE-14]]:11}:".a = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-13]]:5-[[@LINE-13]]:11}:".b = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".c = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".d = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:5-[[@LINE-12]]:11}:".e = 1"
namespace GH63759 {
struct C {
@@ -268,39 +248,3 @@ void foo() {
//
}
}
-
-namespace reorder_derived {
-struct col {
- int r;
- int g;
- int b;
-};
-
-struct point {
- float x;
- float y;
- float z;
-};
-
-struct lols : public col, public point {
- int z2;
- int z1;
-};
-
-void fosas() {
- lols a {
- {.b = 1, .g = 2, .r = 3},
- { .z = 1, .y=2, .x = 3 },
- .z1 = 1,
- .z2 = 2,
- };
-}
-// CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:6-[[@LINE-6]]:12}:".r = 3"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:14-[[@LINE-7]]:20}:".g = 2"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:22-[[@LINE-8]]:28}:".b = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:15-[[@LINE-8]]:19}:".y=2"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:21-[[@LINE-9]]:28}:".z = 1"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:7-[[@LINE-10]]:13}:".x = 3"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z2 = 2"
-// CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:5-[[@LINE-10]]:12}:".z1 = 1"
-} // namespace reorder_derived
>From cb96231e700a8fa259c4172d17039985e76314e2 Mon Sep 17 00:00:00 2001
From: Mythreya <git at mythreya.dev>
Date: Fri, 19 Dec 2025 22:34:38 -0800
Subject: [PATCH 5/5] Update release notes
---
clang/docs/ReleaseNotes.rst | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 994ac444d4aa1..ba14a50c1f177 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -493,6 +493,9 @@ Improvements to Clang's diagnostics
carries messages like 'In file included from ...' or 'In module ...'.
Now the include/import locations are written into `sarif.run.result.relatedLocations`.
+- Clang now generates a fix-it for C++20 designated initializers when the
+ initializers do not match the declaration order in the structure.
+
Improvements to Clang's time-trace
----------------------------------
More information about the cfe-commits
mailing list