https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/173136
>From 4b5b1dcd3cfd26b0192905f8679ec29967e36f27 Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Thu, 18 Dec 2025 23:21:50 -0800 Subject: [PATCH 1/6] [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 <[email protected]> Date: Thu, 18 Dec 2025 23:32:09 -0800 Subject: [PATCH 2/6] 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 <[email protected]> Date: Fri, 19 Dec 2025 02:21:22 -0800 Subject: [PATCH 3/6] 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 <[email protected]> Date: Fri, 19 Dec 2025 02:21:22 -0800 Subject: [PATCH 4/6] 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 <[email protected]> Date: Fri, 19 Dec 2025 22:34:38 -0800 Subject: [PATCH 5/6] 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 ---------------------------------- >From feb3a0efdb672c0b8dc1bc09a0b0be4cb0a1cfd6 Mon Sep 17 00:00:00 2001 From: Mythreya <[email protected]> Date: Sat, 20 Dec 2025 17:20:03 -0800 Subject: [PATCH 6/6] code review --- clang/lib/Sema/SemaInit.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 6decf0d809153..fc2d62d767b7e 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3095,7 +3095,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } const auto GenerateDesignatedInitReorderingFixit = - [&](SemaBase::SemaDiagnosticBuilder &Diags) { + [&](SemaBase::SemaDiagnosticBuilder &Diag) { struct ReorderInfo { int Pos{}; const Expr *InitExpr{}; @@ -3107,11 +3107,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, const auto *CxxRecord = IList->getSemanticForm()->getType()->getAsCXXRecordDecl(); - for (const auto &Field : CxxRecord->fields()) { + for (const FieldDecl *Field : CxxRecord->fields()) MemberNameInx[Field->getIdentifier()] = Field->getFieldIndex(); - } - for (const auto *Init : IList->inits()) { + for (const Expr *Init : IList->inits()) { if (const auto *DI = dyn_cast_if_present<DesignatedInitExpr>(Init)) { // We expect only one Designator @@ -3148,8 +3147,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, const auto InitText = Lexer::getSourceText(CharRange, SM, LangOpts); - Diags << FixItHint::CreateReplacement(OrigExpr->getSourceRange(), - InitText.str()); + Diag << FixItHint::CreateReplacement(OrigExpr->getSourceRange(), + InitText.str()); } }; @@ -3162,10 +3161,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, unsigned OldIndex = StructuredIndex - 1; if (StructuredList && OldIndex <= StructuredList->getNumInits()) { if (Expr *PrevInit = StructuredList->getInit(OldIndex)) { - auto Diags = SemaRef.Diag(PrevInit->getBeginLoc(), - diag::note_previous_field_init) - << PrevField << PrevInit->getSourceRange(); - GenerateDesignatedInitReorderingFixit(Diags); + auto Diag = SemaRef.Diag(PrevInit->getBeginLoc(), + diag::note_previous_field_init) + << PrevField << PrevInit->getSourceRange(); + GenerateDesignatedInitReorderingFixit(Diag); } } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
