https://github.com/vvuksanovic updated 
https://github.com/llvm/llvm-project/pull/142150

>From 69381c74c9c3adf97770cdd2e72f0bd8d862e33c Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vladimir.vuksano...@htecgroup.com>
Date: Tue, 22 Jul 2025 02:50:02 -0700
Subject: [PATCH 1/3] [clang-reorder-fields] Refactor the new order information

Move the new fields order information to a new struct.
---
 .../ReorderFieldsAction.cpp                   | 82 +++++++++++--------
 1 file changed, 48 insertions(+), 34 deletions(-)

diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp 
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index ea0207619fb2b..e5bdf9ab5957e 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -81,6 +81,20 @@ getNewFieldsOrder(const RecordDecl *Definition,
   return NewFieldsOrder;
 }
 
+struct ReorderedStruct {
+public:
+  ReorderedStruct(const RecordDecl *Decl, ArrayRef<unsigned> NewFieldsOrder)
+      : Definition(Decl), NewFieldsOrder(NewFieldsOrder),
+        NewFieldsPositions(NewFieldsOrder.size()) {
+    for (unsigned I = 0; I < NewFieldsPositions.size(); ++I)
+      NewFieldsPositions[NewFieldsOrder[I]] = I;
+  }
+
+  const RecordDecl *Definition;
+  ArrayRef<unsigned> NewFieldsOrder;
+  SmallVector<unsigned, 4> NewFieldsPositions;
+};
+
 // FIXME: error-handling
 /// Replaces one range of source code by another.
 static void
@@ -194,33 +208,33 @@ static SourceRange getFullFieldSourceRange(const 
FieldDecl &Field,
 /// different accesses (public/protected/private) is not supported.
 /// \returns true on success.
 static bool reorderFieldsInDefinition(
-    const RecordDecl *Definition, ArrayRef<unsigned> NewFieldsOrder,
-    const ASTContext &Context,
+    const ReorderedStruct &RS, const ASTContext &Context,
     std::map<std::string, tooling::Replacements> &Replacements) {
-  assert(Definition && "Definition is null");
+  assert(RS.Definition && "Definition is null");
 
   SmallVector<const FieldDecl *, 10> Fields;
-  for (const auto *Field : Definition->fields())
+  for (const auto *Field : RS.Definition->fields())
     Fields.push_back(Field);
 
   // Check that the permutation of the fields doesn't change the accesses
-  for (const auto *Field : Definition->fields()) {
+  for (const auto *Field : RS.Definition->fields()) {
     const auto FieldIndex = Field->getFieldIndex();
-    if (Field->getAccess() != Fields[NewFieldsOrder[FieldIndex]]->getAccess()) 
{
+    if (Field->getAccess() !=
+        Fields[RS.NewFieldsOrder[FieldIndex]]->getAccess()) {
       llvm::errs() << "Currently reordering of fields with different accesses "
                       "is not supported\n";
       return false;
     }
   }
 
-  for (const auto *Field : Definition->fields()) {
+  for (const auto *Field : RS.Definition->fields()) {
     const auto FieldIndex = Field->getFieldIndex();
-    if (FieldIndex == NewFieldsOrder[FieldIndex])
+    if (FieldIndex == RS.NewFieldsOrder[FieldIndex])
       continue;
-    addReplacement(
-        getFullFieldSourceRange(*Field, Context),
-        getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context),
-        Context, Replacements);
+    addReplacement(getFullFieldSourceRange(*Field, Context),
+                   getFullFieldSourceRange(
+                       *Fields[RS.NewFieldsOrder[FieldIndex]], Context),
+                   Context, Replacements);
   }
   return true;
 }
@@ -231,7 +245,7 @@ static bool reorderFieldsInDefinition(
 /// fields. Thus, we need to ensure that we reorder just the initializers that
 /// are present.
 static void reorderFieldsInConstructor(
-    const CXXConstructorDecl *CtorDecl, ArrayRef<unsigned> NewFieldsOrder,
+    const CXXConstructorDecl *CtorDecl, const ReorderedStruct &RS,
     ASTContext &Context,
     std::map<std::string, tooling::Replacements> &Replacements) {
   assert(CtorDecl && "Constructor declaration is null");
@@ -243,10 +257,6 @@ static void reorderFieldsInConstructor(
   // Thus this assert needs to be after the previous checks.
   assert(CtorDecl->isThisDeclarationADefinition() && "Not a definition");
 
-  SmallVector<unsigned, 10> NewFieldsPositions(NewFieldsOrder.size());
-  for (unsigned i = 0, e = NewFieldsOrder.size(); i < e; ++i)
-    NewFieldsPositions[NewFieldsOrder[i]] = i;
-
   SmallVector<const CXXCtorInitializer *, 10> OldWrittenInitializersOrder;
   SmallVector<const CXXCtorInitializer *, 10> NewWrittenInitializersOrder;
   for (const auto *Initializer : CtorDecl->inits()) {
@@ -257,8 +267,8 @@ static void reorderFieldsInConstructor(
     const FieldDecl *ThisM = Initializer->getMember();
     const auto UsedMembers = findMembersUsedInInitExpr(Initializer, Context);
     for (const FieldDecl *UM : UsedMembers) {
-      if (NewFieldsPositions[UM->getFieldIndex()] >
-          NewFieldsPositions[ThisM->getFieldIndex()]) {
+      if (RS.NewFieldsPositions[UM->getFieldIndex()] >
+          RS.NewFieldsPositions[ThisM->getFieldIndex()]) {
         DiagnosticsEngine &DiagEngine = Context.getDiagnostics();
         auto Description = ("reordering field " + UM->getName() + " after " +
                             ThisM->getName() + " makes " + UM->getName() +
@@ -276,8 +286,8 @@ static void reorderFieldsInConstructor(
   auto ByFieldNewPosition = [&](const CXXCtorInitializer *LHS,
                                 const CXXCtorInitializer *RHS) {
     assert(LHS && RHS);
-    return NewFieldsPositions[LHS->getMember()->getFieldIndex()] <
-           NewFieldsPositions[RHS->getMember()->getFieldIndex()];
+    return RS.NewFieldsPositions[LHS->getMember()->getFieldIndex()] <
+           RS.NewFieldsPositions[RHS->getMember()->getFieldIndex()];
   };
   llvm::sort(NewWrittenInitializersOrder, ByFieldNewPosition);
   assert(OldWrittenInitializersOrder.size() ==
@@ -294,8 +304,8 @@ static void reorderFieldsInConstructor(
 /// At the moment partial initialization is not supported.
 /// \returns true on success
 static bool reorderFieldsInInitListExpr(
-    const InitListExpr *InitListEx, ArrayRef<unsigned> NewFieldsOrder,
-    const ASTContext &Context,
+    const InitListExpr *InitListEx, const ReorderedStruct &RS,
+    ASTContext &Context,
     std::map<std::string, tooling::Replacements> &Replacements) {
   assert(InitListEx && "Init list expression is null");
   // We care only about InitListExprs which originate from source code.
@@ -309,15 +319,16 @@ static bool reorderFieldsInInitListExpr(
   // If there are no initializers we do not need to change anything.
   if (!InitListEx->getNumInits())
     return true;
-  if (InitListEx->getNumInits() != NewFieldsOrder.size()) {
+  if (InitListEx->getNumInits() != RS.NewFieldsOrder.size()) {
     llvm::errs() << "Currently only full initialization is supported\n";
     return false;
   }
   for (unsigned i = 0, e = InitListEx->getNumInits(); i < e; ++i)
-    if (i != NewFieldsOrder[i])
-      addReplacement(InitListEx->getInit(i)->getSourceRange(),
-                     InitListEx->getInit(NewFieldsOrder[i])->getSourceRange(),
-                     Context, Replacements);
+    if (i != RS.NewFieldsOrder[i])
+      addReplacement(
+          InitListEx->getInit(i)->getSourceRange(),
+          InitListEx->getInit(RS.NewFieldsOrder[i])->getSourceRange(), Context,
+          Replacements);
   return true;
 }
 
@@ -345,7 +356,9 @@ class ReorderingConsumer : public ASTConsumer {
         getNewFieldsOrder(RD, DesiredFieldsOrder);
     if (NewFieldsOrder.empty())
       return;
-    if (!reorderFieldsInDefinition(RD, NewFieldsOrder, Context, Replacements))
+    ReorderedStruct RS{RD, NewFieldsOrder};
+
+    if (!reorderFieldsInDefinition(RS, Context, Replacements))
       return;
 
     // CXXRD will be nullptr if C code (not C++) is being processed.
@@ -353,24 +366,25 @@ class ReorderingConsumer : public ASTConsumer {
     if (CXXRD)
       for (const auto *C : CXXRD->ctors())
         if (const auto *D = dyn_cast<CXXConstructorDecl>(C->getDefinition()))
-          reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D),
-                                     NewFieldsOrder, Context, Replacements);
+          reorderFieldsInConstructor(cast<const CXXConstructorDecl>(D), RS,
+                                     Context, Replacements);
 
     // We only need to reorder init list expressions for
     // plain C structs or C++ aggregate types.
     // For other types the order of constructor parameters is used,
     // which we don't change at the moment.
     // Now (v0) partial initialization is not supported.
-    if (!CXXRD || CXXRD->isAggregate())
+    if (!CXXRD || CXXRD->isAggregate()) {
       for (auto Result :
            match(initListExpr(hasType(equalsNode(RD))).bind("initListExpr"),
                  Context))
         if (!reorderFieldsInInitListExpr(
-                Result.getNodeAs<InitListExpr>("initListExpr"), NewFieldsOrder,
-                Context, Replacements)) {
+                Result.getNodeAs<InitListExpr>("initListExpr"), RS, Context,
+                Replacements)) {
           Replacements.clear();
           return;
         }
+    }
   }
 };
 } // end anonymous namespace

>From 144f8784311fce8f55c5dabaaec6fe78d7cfcd06 Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vladimir.vuksano...@htecgroup.com>
Date: Tue, 22 Jul 2025 05:57:12 -0700
Subject: [PATCH 2/3] [clang-reorder-fields] Support designated initializers

Initializer lists with designators, missing elements or omitted braces can now 
be rewritten. Any missing designators are added and they get sorted according 
to the new order.

```
struct Foo {
int a;
int b;
int c;
};
struct Foo foo = { .a = 1, 2, 3 }
```

when reordering elements to "b,a,c" becomes:

```
struct Foo {
int b;
int a;
int c;
};
struct Foo foo = { .b = 2, .a = 1, .c = 3 }
```
---
 .../clang-reorder-fields/CMakeLists.txt       |   1 +
 .../clang-reorder-fields/Designator.cpp       | 199 +++++++++++++++
 .../clang-reorder-fields/Designator.h         | 145 +++++++++++
 .../ReorderFieldsAction.cpp                   | 241 ++++++++++++++++--
 .../DesignatedInitializerList.c               |  31 +++
 5 files changed, 597 insertions(+), 20 deletions(-)
 create mode 100644 clang-tools-extra/clang-reorder-fields/Designator.cpp
 create mode 100644 clang-tools-extra/clang-reorder-fields/Designator.h
 create mode 100644 
clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c

diff --git a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt 
b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
index 2fdeb65d89767..dec0287b26873 100644
--- a/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
+++ b/clang-tools-extra/clang-reorder-fields/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 )
 
 add_clang_library(clangReorderFields STATIC
+  Designator.cpp
   ReorderFieldsAction.cpp
 
   DEPENDS
diff --git a/clang-tools-extra/clang-reorder-fields/Designator.cpp 
b/clang-tools-extra/clang-reorder-fields/Designator.cpp
new file mode 100644
index 0000000000000..7d4edf0a8b63c
--- /dev/null
+++ b/clang-tools-extra/clang-reorder-fields/Designator.cpp
@@ -0,0 +1,199 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of the DesignatorIter and Designators
+/// utility classes.
+///
+//===----------------------------------------------------------------------===//
+
+#include "Designator.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace reorder_fields {
+
+DesignatorIter &DesignatorIter::operator++() {
+  assert(!isFinished() && "Iterator is already finished");
+  switch (Tag) {
+  case STRUCT:
+    if (StructIt.Record->isUnion()) {
+      // Union always finishes on first increment.
+      StructIt.Field = StructIt.Record->field_end();
+      Type = QualType();
+      break;
+    }
+    ++StructIt.Field;
+    if (StructIt.Field != StructIt.Record->field_end()) {
+      Type = StructIt.Field->getType();
+    } else {
+      Type = QualType();
+    }
+    break;
+  case ARRAY:
+    ++ArrayIt.Index;
+    break;
+  case ARRAY_RANGE:
+    ArrayIt.Index = ArrayRangeIt.End + 1;
+    ArrayIt.Size = ArrayRangeIt.Size;
+    Tag = ARRAY;
+    break;
+  }
+  return *this;
+}
+
+bool DesignatorIter::isFinished() {
+  switch (Tag) {
+  case STRUCT:
+    return StructIt.Field == StructIt.Record->field_end();
+  case ARRAY:
+    return ArrayIt.Index == ArrayIt.Size;
+  case ARRAY_RANGE:
+    return ArrayRangeIt.End == ArrayRangeIt.Size;
+  }
+  return false;
+}
+
+Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr 
*ILE,
+                         const ASTContext &Context) {
+  for (const auto &D : DIE->designators()) {
+    if (D.isFieldDesignator()) {
+      RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent();
+      for (auto FieldIt = DesignatorRecord->field_begin();
+           FieldIt != DesignatorRecord->field_end(); ++FieldIt) {
+        if (*FieldIt == D.getFieldDecl()) {
+          DesignatorList.push_back(
+              {FieldIt->getType(), FieldIt, DesignatorRecord});
+          break;
+        }
+      }
+    } else {
+      const QualType CurrentType = DesignatorList.empty()
+                                       ? ILE->getType()
+                                       : DesignatorList.back().getType();
+      const ConstantArrayType *CAT =
+          Context.getAsConstantArrayType(CurrentType);
+      if (!CAT) {
+        // Non-constant-sized arrays are not supported.
+        DesignatorList.clear();
+        return;
+      }
+      if (D.isArrayDesignator()) {
+        DesignatorList.push_back({CAT->getElementType(),
+                                  DIE->getArrayIndex(D)
+                                      ->EvaluateKnownConstInt(Context)
+                                      .getZExtValue(),
+                                  CAT->getSize().getZExtValue()});
+      } else if (D.isArrayRangeDesignator()) {
+        DesignatorList.push_back({CAT->getElementType(),
+                                  DIE->getArrayRangeStart(D)
+                                      ->EvaluateKnownConstInt(Context)
+                                      .getZExtValue(),
+                                  DIE->getArrayRangeEnd(D)
+                                      ->EvaluateKnownConstInt(Context)
+                                      .getZExtValue(),
+                                  CAT->getSize().getZExtValue()});
+      } else {
+        llvm_unreachable("Unexpected designator kind");
+      }
+    }
+  }
+}
+
+bool Designators::increment(const InitListExpr *ILE, const Expr *Init,
+                            const ASTContext &Context) {
+  if (DesignatorList.empty()) {
+    // First field is not designated. Initialize to the first field or
+    // array index.
+    if (ILE->getType()->isArrayType()) {
+      const ConstantArrayType *CAT =
+          Context.getAsConstantArrayType(ILE->getType());
+      // Only constant size arrays are supported.
+      if (!CAT) {
+        DesignatorList.clear();
+        return false;
+      }
+      DesignatorList.push_back(
+          {CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
+    } else {
+      const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
+      DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
+                                DesignatorRD->field_begin(), DesignatorRD});
+    }
+  } else {
+    while (!DesignatorList.empty()) {
+      auto &CurrentDesignator = DesignatorList.back();
+      ++CurrentDesignator;
+      if (CurrentDesignator.isFinished()) {
+        DesignatorList.pop_back();
+        continue;
+      }
+      break;
+    }
+  }
+
+  // If the designator list is empty at this point, then there must be excess
+  // elements in the initializer list. They are not currently supported.
+  if (DesignatorList.empty())
+    return false;
+
+  // Check for missing braces. If the types don't match then there are
+  // missing braces.
+  while (true) {
+    const QualType T = DesignatorList.back().getType();
+    // If the types match, there are no missing braces.
+    if (Init->getType() == T)
+      break;
+
+    // If the current type is a struct, then get its first field.
+    if (T->isRecordType()) {
+      DesignatorList.push_back({T->getAsRecordDecl()->field_begin()->getType(),
+                                T->getAsRecordDecl()->field_begin(),
+                                T->getAsRecordDecl()});
+      continue;
+    }
+    // If the current type is an array, then get its first element.
+    if (T->isArrayType()) {
+      DesignatorList.push_back(
+          {Context.getAsArrayType(T)->getElementType(), 0,
+           Context.getAsConstantArrayType(T)->getSize().getZExtValue()});
+      continue;
+    }
+
+    // The initializer doesn't match the expected type. The initializer list is
+    // invalid.
+    return false;
+  }
+
+  return true;
+}
+
+std::string Designators::toString() const {
+  if (DesignatorList.empty())
+    return "";
+  std::string Designator = "";
+  for (auto &I : DesignatorList) {
+    switch (I.getTag()) {
+    case DesignatorIter::STRUCT:
+      Designator += "." + I.getStructIter()->getName().str();
+      break;
+    case DesignatorIter::ARRAY:
+      Designator += "[" + std::to_string(I.getArrayIndex()) + "]";
+      break;
+    case DesignatorIter::ARRAY_RANGE:
+      Designator += "[" + std::to_string(I.getArrayRangeStart()) + "..." +
+                    std::to_string(I.getArrayRangeEnd()) + "]";
+    }
+  }
+  Designator += " = ";
+  return Designator;
+}
+
+} // namespace reorder_fields
+} // namespace clang
diff --git a/clang-tools-extra/clang-reorder-fields/Designator.h 
b/clang-tools-extra/clang-reorder-fields/Designator.h
new file mode 100644
index 0000000000000..66b74f2571110
--- /dev/null
+++ b/clang-tools-extra/clang-reorder-fields/Designator.h
@@ -0,0 +1,145 @@
+//===-- tools/extra/clang-reorder-fields/utils/Designator.h -----*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declarations of the DesignatorIter and Designators
+/// utility class.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace reorder_fields {
+
+class DesignatorIter {
+public:
+  enum Kind { STRUCT, ARRAY, ARRAY_RANGE };
+
+  DesignatorIter(const QualType Type, RecordDecl::field_iterator Field,
+                 const RecordDecl *RD)
+      : Tag(STRUCT), Type(Type), StructIt({Field, RD}) {}
+
+  DesignatorIter(const QualType Type, uint64_t Idx, uint64_t Size)
+      : Tag(ARRAY), Type(Type), ArrayIt({Idx, Size}) {}
+
+  DesignatorIter(const QualType Type, uint64_t Start, uint64_t End,
+                 uint64_t Size)
+      : Tag(ARRAY_RANGE), Type(Type), ArrayRangeIt({Start, End, Size}) {}
+
+  /// Moves the iterator to the next element.
+  DesignatorIter &operator++();
+
+  /// Checks if the iterator has iterated through all elements.
+  bool isFinished();
+
+  Kind getTag() const { return Tag; }
+  QualType getType() const { return Type; }
+
+  const RecordDecl::field_iterator getStructIter() const {
+    assert(Tag == STRUCT && "Must be a field designator");
+    return StructIt.Field;
+  }
+
+  const RecordDecl *getStructDecl() const {
+    assert(Tag == STRUCT && "Must be a field designator");
+    return StructIt.Record;
+  }
+
+  uint64_t getArrayIndex() const {
+    assert(Tag == ARRAY && "Must be an array designator");
+    return ArrayIt.Index;
+  }
+
+  uint64_t getArrayRangeStart() const {
+    assert(Tag == ARRAY_RANGE && "Must be an array range designator");
+    return ArrayRangeIt.Start;
+  }
+
+  uint64_t getArrayRangeEnd() const {
+    assert(Tag == ARRAY_RANGE && "Must be an array range designator");
+    return ArrayRangeIt.End;
+  }
+
+  uint64_t getArraySize() const {
+    assert((Tag == ARRAY || Tag == ARRAY_RANGE) &&
+           "Must be an array or range designator");
+    if (Tag == ARRAY)
+      return ArrayIt.Size;
+    return ArrayRangeIt.Size;
+  }
+
+private:
+  /// Type of the designator.
+  Kind Tag;
+
+  /// Type of the designated entry. For arrays this is the type of the element.
+  QualType Type;
+
+  /// Field designator has the iterator to the field and the record the field
+  /// is declared in.
+  struct StructIter {
+    RecordDecl::field_iterator Field;
+    const RecordDecl *Record;
+  };
+
+  /// Array designator has an index and size of the array.
+  struct ArrayIter {
+    uint64_t Index;
+    uint64_t Size;
+  };
+
+  /// Array range designator has a start and end index and size of the array.
+  struct ArrayRangeIter {
+    uint64_t Start;
+    uint64_t End;
+    uint64_t Size;
+  };
+
+  union {
+    StructIter StructIt;
+    ArrayIter ArrayIt;
+    ArrayRangeIter ArrayRangeIt;
+  };
+};
+
+class Designators {
+public:
+  Designators() = default;
+  Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
+              const ASTContext &Context);
+
+  /// Moves the designators to the next initializer in the struct/array. If the
+  /// type of next initializer doesn't match the expected type then there are
+  /// omitted braces and we add new designators to reflect that.
+  bool increment(const InitListExpr *ILE, const Expr *Init,
+                 const ASTContext &Context);
+
+  /// Gets a string representation from a list of designators. This string will
+  /// be inserted before an initializer expression to make it designated.
+  std::string toString() const;
+
+  size_t size() const { return DesignatorList.size(); }
+
+  const DesignatorIter &operator[](unsigned Idx) const {
+    return DesignatorList[Idx];
+  }
+
+private:
+  SmallVector<DesignatorIter, 1> DesignatorList;
+};
+
+} // namespace reorder_fields
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp 
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index e5bdf9ab5957e..0c6841e298cc7 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -13,6 +13,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "ReorderFieldsAction.h"
+#include "Designator.h"
 #include "clang/AST/AST.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -23,6 +24,7 @@
 #include "clang/Tooling/Refactoring.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <string>
 
 namespace clang {
@@ -96,6 +98,29 @@ struct ReorderedStruct {
 };
 
 // FIXME: error-handling
+/// Replaces a range of source code by the specified text.
+static void
+addReplacement(SourceRange Old, StringRef New, const ASTContext &Context,
+               std::map<std::string, tooling::Replacements> &Replacements) {
+  tooling::Replacement R(Context.getSourceManager(),
+                         CharSourceRange::getTokenRange(Old), New,
+                         Context.getLangOpts());
+  consumeError(Replacements[std::string(R.getFilePath())].add(R));
+}
+
+/// Replaces one range of source code by another and adds a prefix.
+static void
+addReplacement(SourceRange Old, SourceRange New, StringRef Prefix,
+               const ASTContext &Context,
+               std::map<std::string, tooling::Replacements> &Replacements) {
+  std::string NewText =
+      (Prefix + Lexer::getSourceText(CharSourceRange::getTokenRange(New),
+                                     Context.getSourceManager(),
+                                     Context.getLangOpts()))
+          .str();
+  addReplacement(Old, NewText, Context, Replacements);
+}
+
 /// Replaces one range of source code by another.
 static void
 addReplacement(SourceRange Old, SourceRange New, const ASTContext &Context,
@@ -103,10 +128,7 @@ addReplacement(SourceRange Old, SourceRange New, const 
ASTContext &Context,
   StringRef NewText =
       Lexer::getSourceText(CharSourceRange::getTokenRange(New),
                            Context.getSourceManager(), Context.getLangOpts());
-  tooling::Replacement R(Context.getSourceManager(),
-                         CharSourceRange::getTokenRange(Old), NewText,
-                         Context.getLangOpts());
-  consumeError(Replacements[std::string(R.getFilePath())].add(R));
+  addReplacement(Old, NewText.str(), Context, Replacements);
 }
 
 /// Find all member fields used in the given init-list initializer expr
@@ -299,6 +321,98 @@ static void reorderFieldsInConstructor(
                      Replacements);
 }
 
+/// Replacement for broken InitListExpr::isExplicit function.
+/// FIXME: Remove when InitListExpr::isExplicit is fixed.
+static bool isImplicitILE(const InitListExpr *ILE, const ASTContext &Context) {
+  // The ILE is implicit if either:
+  // - The left brace loc of the ILE matches the start of first init expression
+  //   (for non designated decls)
+  // - The right brace loc of the ILE matches the end of first init expression
+  //   (for designated decls)
+  // The first init expression should be taken from the syntactic form, but
+  // since the ILE could be implicit, there might not be a syntactic form.
+  // For that reason we have to check against all init expressions.
+  for (const Expr *Init : ILE->inits()) {
+    if (ILE->getLBraceLoc() == Init->getBeginLoc() ||
+        ILE->getRBraceLoc() == Init->getEndLoc())
+      return true;
+  }
+  return false;
+}
+
+/// Compares compatible designators according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignators(const DesignatorIter &Lhs, const DesignatorIter &Rhs,
+                          const ReorderedStruct &Struct) {
+  switch (Lhs.getTag()) {
+  case DesignatorIter::STRUCT:
+    assert(Rhs.getTag() == DesignatorIter::STRUCT &&
+           "Incompatible designators");
+    assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&
+           "Incompatible structs");
+    // Use the new layout for reordered struct.
+    if (Struct.Definition == Lhs.getStructDecl()) {
+      return Struct.NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] -
+             Struct.NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];
+    }
+    return Lhs.getStructIter()->getFieldIndex() -
+           Rhs.getStructIter()->getFieldIndex();
+  case DesignatorIter::ARRAY:
+  case DesignatorIter::ARRAY_RANGE:
+    // Array designators can be compared to array range designators.
+    assert((Rhs.getTag() == DesignatorIter::ARRAY ||
+            Rhs.getTag() == DesignatorIter::ARRAY_RANGE) &&
+           "Incompatible designators");
+    size_t LhsIdx = Lhs.getTag() == DesignatorIter::ARRAY
+                        ? Lhs.getArrayIndex()
+                        : Lhs.getArrayRangeStart();
+    size_t RhsIdx = Rhs.getTag() == DesignatorIter::ARRAY
+                        ? Rhs.getArrayIndex()
+                        : Rhs.getArrayRangeStart();
+    return LhsIdx - RhsIdx;
+  }
+  llvm_unreachable("Invalid designator tag");
+}
+
+/// Compares compatible designator lists according to the new struct order.
+/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
+/// they are equal.
+static int cmpDesignatorLists(const Designators &Lhs, const Designators &Rhs,
+                              const ReorderedStruct &Reorders) {
+  for (unsigned Idx = 0, Size = std::min(Lhs.size(), Rhs.size()); Idx < Size;
+       ++Idx) {
+    int DesignatorComp = cmpDesignators(Lhs[Idx], Rhs[Idx], Reorders);
+    // If the current designators are not equal, return the result
+    if (DesignatorComp != 0)
+      return DesignatorComp;
+    // Otherwise, continue to the next pair.
+  }
+  // If all common designators were equal, compare the sizes of the designator
+  // lists.
+  return Lhs.size() - Rhs.size();
+}
+
+/// Finds the semantic form of the first explicit ancestor of the given
+/// initializer list including itself.
+static const InitListExpr *getExplicitILE(const InitListExpr *ILE,
+                                          ASTContext &Context) {
+  if (!isImplicitILE(ILE, Context))
+    return ILE;
+  const InitListExpr *TopLevelILE = ILE;
+  DynTypedNodeList Parents = Context.getParents(*TopLevelILE);
+  while (!Parents.empty() && Parents.begin()->get<InitListExpr>()) {
+    TopLevelILE = Parents.begin()->get<InitListExpr>();
+    Parents = Context.getParents(*TopLevelILE);
+    if (!isImplicitILE(TopLevelILE, Context))
+      break;
+  }
+  if (!TopLevelILE->isSemanticForm()) {
+    return TopLevelILE->getSemanticForm();
+  }
+  return TopLevelILE;
+}
+
 /// Reorders initializers in the brace initialization of an aggregate.
 ///
 /// At the moment partial initialization is not supported.
@@ -308,27 +422,114 @@ static bool reorderFieldsInInitListExpr(
     ASTContext &Context,
     std::map<std::string, tooling::Replacements> &Replacements) {
   assert(InitListEx && "Init list expression is null");
-  // We care only about InitListExprs which originate from source code.
-  // Implicit InitListExprs are created by the semantic analyzer.
-  if (!InitListEx->isExplicit())
+  // Only process semantic forms of initializer lists.
+  if (!InitListEx->isSemanticForm()) {
     return true;
-  // The method InitListExpr::getSyntacticForm may return nullptr indicating
-  // that the current initializer list also serves as its syntactic form.
-  if (const auto *SyntacticForm = InitListEx->getSyntacticForm())
-    InitListEx = SyntacticForm;
+  }
+
   // If there are no initializers we do not need to change anything.
   if (!InitListEx->getNumInits())
     return true;
-  if (InitListEx->getNumInits() != RS.NewFieldsOrder.size()) {
-    llvm::errs() << "Currently only full initialization is supported\n";
-    return false;
+
+  // We care only about InitListExprs which originate from source code.
+  // Implicit InitListExprs are created by the semantic analyzer.
+  // We find the first parent InitListExpr that exists in source code and
+  // process it. This is necessary because of designated initializer lists and
+  // possible omitted braces.
+  InitListEx = getExplicitILE(InitListEx, Context);
+
+  // Find if there are any designated initializations or implicit values. If 
all
+  // initializers are present and none have designators then just reorder them
+  // normally. Otherwise, designators are added to all initializers and they 
are
+  // sorted in the new order.
+  bool ShouldAddDesignators = false;
+  // The method InitListExpr::getSyntacticForm may return nullptr indicating
+  // that the current initializer list also serves as its syntactic form.
+  const InitListExpr *SyntacticInitListEx = InitListEx;
+  if (const InitListExpr *SynILE = InitListEx->getSyntacticForm()) {
+    // Do not rewrite zero initializers. This check is only valid for syntactic
+    // forms.
+    if (SynILE->isIdiomaticZeroInitializer(Context.getLangOpts()))
+      return true;
+
+    ShouldAddDesignators = InitListEx->getNumInits() != SynILE->getNumInits() 
||
+                           llvm::any_of(SynILE->inits(), [](const Expr *Init) {
+                             return isa<DesignatedInitExpr>(Init);
+                           });
+
+    SyntacticInitListEx = SynILE;
+  } else {
+    // If there is no syntactic form, there can be no designators. Instead,
+    // there might be implicit values.
+    ShouldAddDesignators =
+        (RS.NewFieldsOrder.size() != InitListEx->getNumInits()) ||
+        llvm::any_of(InitListEx->inits(), [&Context](const Expr *Init) {
+          return isa<ImplicitValueInitExpr>(Init) ||
+                 (isa<InitListExpr>(Init) &&
+                  isImplicitILE(dyn_cast<InitListExpr>(Init), Context));
+        });
+  }
+
+  if (ShouldAddDesignators) {
+    // Designators are only supported from C++20.
+    if (Context.getLangOpts().CPlusPlus && !Context.getLangOpts().CPlusPlus20) 
{
+      llvm::errs()
+          << "Currently only full initialization is supported for C++\n";
+      return false;
+    }
+
+    // Handle case when some fields are designated. Some fields can be
+    // missing. Insert any missing designators and reorder the expressions
+    // according to the new order.
+    Designators CurrentDesignators{};
+    // Remember each initializer expression along with its designators. They 
are
+    // sorted later to determine the correct order.
+    std::vector<std::pair<Designators, const Expr *>> Rewrites;
+    for (const Expr *Init : SyntacticInitListEx->inits()) {
+      if (const auto *DIE = dyn_cast_or_null<DesignatedInitExpr>(Init)) {
+        CurrentDesignators = {DIE, SyntacticInitListEx, Context};
+
+        // Use the child of the DesignatedInitExpr. This way designators are
+        // always replaced.
+        Rewrites.push_back({CurrentDesignators, DIE->getInit()});
+      } else {
+        // Find the next field.
+        if (!CurrentDesignators.increment(SyntacticInitListEx, Init, Context)) 
{
+          llvm::errs() << "Unsupported initializer list\n";
+          return false;
+        }
+
+        // Do not rewrite implicit values. They just had to be processed to
+        // find the correct designator.
+        if (!isa<ImplicitValueInitExpr>(Init))
+          Rewrites.push_back({CurrentDesignators, Init});
+      }
+    }
+
+    // Sort the designators according to the new order.
+    llvm::sort(Rewrites, [&RS](const auto &Lhs, const auto &Rhs) {
+      return cmpDesignatorLists(Lhs.first, Rhs.first, RS) < 0;
+    });
+
+    for (unsigned i = 0, e = Rewrites.size(); i < e; ++i) {
+      addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),
+                     Rewrites[i].second->getSourceRange(),
+                     Rewrites[i].first.toString(), Context, Replacements);
+    }
+  } else {
+    // Handle excess initializers by leaving them unchanged.
+    assert(SyntacticInitListEx->getNumInits() >= InitListEx->getNumInits());
+
+    // All field initializers are present and none have designators. They can 
be
+    // reordered normally.
+    for (unsigned i = 0, e = RS.NewFieldsOrder.size(); i < e; ++i) {
+      if (i != RS.NewFieldsOrder[i])
+        addReplacement(SyntacticInitListEx->getInit(i)->getSourceRange(),
+                       SyntacticInitListEx->getInit(RS.NewFieldsOrder[i])
+                           ->getSourceRange(),
+                       Context, Replacements);
+    }
   }
-  for (unsigned i = 0, e = InitListEx->getNumInits(); i < e; ++i)
-    if (i != RS.NewFieldsOrder[i])
-      addReplacement(
-          InitListEx->getInit(i)->getSourceRange(),
-          InitListEx->getInit(RS.NewFieldsOrder[i])->getSourceRange(), Context,
-          Replacements);
   return true;
 }
 
diff --git 
a/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c 
b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
new file mode 100644
index 0000000000000..c05c296d1b47b
--- /dev/null
+++ b/clang-tools-extra/test/clang-reorder-fields/DesignatedInitializerList.c
@@ -0,0 +1,31 @@
+// RUN: clang-reorder-fields -record-name Foo -fields-order z,w,y,x %s -- | 
FileCheck %s
+
+struct Foo {
+  const int* x; // CHECK:      {{^  double z;}}
+  int y;        // CHECK-NEXT: {{^  int w;}}
+  double z;     // CHECK-NEXT: {{^  int y;}}
+  int w;        // CHECK-NEXT: {{^  const int\* x}}
+};
+
+struct Bar {
+  char a;
+  struct Foo b;
+  char c;
+};
+
+int main() {
+  const int x = 13;
+  struct Foo foo1 = { .x=&x, .y=0, .z=1.29, .w=17 }; // CHECK: {{^ struct Foo 
foo1 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+  struct Foo foo2 = { .x=&x, 0, 1.29, 17 };          // CHECK: {{^ struct Foo 
foo2 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+  struct Foo foo3 = { .y=0, .z=1.29, 17, .x=&x };    // CHECK: {{^ struct Foo 
foo3 = { .z = 1.29, .w = 17, .y = 0, .x = &x };}}
+  struct Foo foo4 = { .y=0, .z=1.29, 17 };           // CHECK: {{^ struct Foo 
foo4 = { .z = 1.29, .w = 17, .y = 0 };}}
+
+  struct Foo foos1[1] = { [0] = {.x=&x, 0, 1.29, 17} };              // CHECK: 
{{^ struct Foo foos1\[1] = { \[0] = {.z = 1.29, .w = 17, .y = 0, .x = &x} };}}
+  struct Foo foos2[1] = { [0].x=&x, [0].y=0, [0].z=1.29, [0].w=17 }; // CHECK: 
{{^ struct Foo foos2\[1] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = 
&x };}}
+  struct Foo foos3[1] = { &x, 0, 1.29, 17 };                         // CHECK: 
{{^ struct Foo foos3\[1] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = 
&x };}}
+  struct Foo foos4[2] = { &x, 0, 1.29, 17, &x, 0, 1.29, 17 };        // CHECK: 
{{^ struct Foo foos4\[2] = { \[0].z = 1.29, \[0].w = 17, \[0].y = 0, \[0].x = 
&x, \[1].z = 1.29, \[1].w = 17, \[1].y = 0, \[1].x = &x };}}
+
+  struct Bar bar1 = { .a='a', &x, 0, 1.29, 17, 'c' }; // CHECK: {{^ struct Bar 
bar1 = { .a = 'a', .b.z = 1.29, .b.w = 17, .b.y = 0, .b.x = &x, .c = 'c' };}}
+
+  return 0;
+}

>From 47344f0cce5004d96307cd0afa6a3da299444802 Mon Sep 17 00:00:00 2001
From: Vladimir Vuksanovic <vladimir.vuksano...@htecgroup.com>
Date: Wed, 20 Aug 2025 12:18:52 +0200
Subject: [PATCH 3/3] fixup! [clang-reorder-fields] Support designated
 initializers

---
 .../clang-reorder-fields/Designator.cpp       |  90 +++++++-----
 .../clang-reorder-fields/Designator.h         |  18 ++-
 .../ReorderFieldsAction.cpp                   | 138 ++++++++++--------
 3 files changed, 143 insertions(+), 103 deletions(-)

diff --git a/clang-tools-extra/clang-reorder-fields/Designator.cpp 
b/clang-tools-extra/clang-reorder-fields/Designator.cpp
index 7d4edf0a8b63c..94418481e4a78 100644
--- a/clang-tools-extra/clang-reorder-fields/Designator.cpp
+++ b/clang-tools-extra/clang-reorder-fields/Designator.cpp
@@ -60,8 +60,37 @@ bool DesignatorIter::isFinished() {
   return false;
 }
 
+Designators::Designators(const Expr *Init, const InitListExpr *ILE,
+                         const ASTContext *Context)
+    : ILE(ILE), Context(Context) {
+  if (ILE->getType()->isArrayType()) {
+    const ConstantArrayType *CAT =
+        Context->getAsConstantArrayType(ILE->getType());
+    // Only constant size arrays are supported.
+    if (!CAT) {
+      DesignatorList.clear();
+      return;
+    }
+    DesignatorList.push_back(
+        {CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
+  } else {
+    const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
+    DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
+                              DesignatorRD->field_begin(), DesignatorRD});
+  }
+
+  // If the designator list is empty at this point, then there must be excess
+  // elements in the initializer list. They are not currently supported.
+  if (DesignatorList.empty())
+    return;
+
+  if (!enterImplicitInitLists(Init))
+    DesignatorList.clear();
+}
+
 Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr 
*ILE,
-                         const ASTContext &Context) {
+                         const ASTContext *Context)
+    : ILE(ILE), Context(Context) {
   for (const auto &D : DIE->designators()) {
     if (D.isFieldDesignator()) {
       RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent();
@@ -78,7 +107,7 @@ Designators::Designators(const DesignatedInitExpr *DIE, 
const InitListExpr *ILE,
                                        ? ILE->getType()
                                        : DesignatorList.back().getType();
       const ConstantArrayType *CAT =
-          Context.getAsConstantArrayType(CurrentType);
+          Context->getAsConstantArrayType(CurrentType);
       if (!CAT) {
         // Non-constant-sized arrays are not supported.
         DesignatorList.clear();
@@ -87,16 +116,16 @@ Designators::Designators(const DesignatedInitExpr *DIE, 
const InitListExpr *ILE,
       if (D.isArrayDesignator()) {
         DesignatorList.push_back({CAT->getElementType(),
                                   DIE->getArrayIndex(D)
-                                      ->EvaluateKnownConstInt(Context)
+                                      ->EvaluateKnownConstInt(*Context)
                                       .getZExtValue(),
                                   CAT->getSize().getZExtValue()});
       } else if (D.isArrayRangeDesignator()) {
         DesignatorList.push_back({CAT->getElementType(),
                                   DIE->getArrayRangeStart(D)
-                                      ->EvaluateKnownConstInt(Context)
+                                      ->EvaluateKnownConstInt(*Context)
                                       .getZExtValue(),
                                   DIE->getArrayRangeEnd(D)
-                                      ->EvaluateKnownConstInt(Context)
+                                      ->EvaluateKnownConstInt(*Context)
                                       .getZExtValue(),
                                   CAT->getSize().getZExtValue()});
       } else {
@@ -106,36 +135,17 @@ Designators::Designators(const DesignatedInitExpr *DIE, 
const InitListExpr *ILE,
   }
 }
 
-bool Designators::increment(const InitListExpr *ILE, const Expr *Init,
-                            const ASTContext &Context) {
-  if (DesignatorList.empty()) {
-    // First field is not designated. Initialize to the first field or
-    // array index.
-    if (ILE->getType()->isArrayType()) {
-      const ConstantArrayType *CAT =
-          Context.getAsConstantArrayType(ILE->getType());
-      // Only constant size arrays are supported.
-      if (!CAT) {
-        DesignatorList.clear();
-        return false;
-      }
-      DesignatorList.push_back(
-          {CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
-    } else {
-      const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
-      DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
-                                DesignatorRD->field_begin(), DesignatorRD});
-    }
-  } else {
-    while (!DesignatorList.empty()) {
-      auto &CurrentDesignator = DesignatorList.back();
-      ++CurrentDesignator;
-      if (CurrentDesignator.isFinished()) {
-        DesignatorList.pop_back();
-        continue;
-      }
-      break;
+bool Designators::advanceToNextField(const Expr *Init) {
+  // Remove all designators that refer to the last field of a struct or final
+  // element of the array.
+  while (!DesignatorList.empty()) {
+    auto &CurrentDesignator = DesignatorList.back();
+    ++CurrentDesignator;
+    if (CurrentDesignator.isFinished()) {
+      DesignatorList.pop_back();
+      continue;
     }
+    break;
   }
 
   // If the designator list is empty at this point, then there must be excess
@@ -143,8 +153,12 @@ bool Designators::increment(const InitListExpr *ILE, const 
Expr *Init,
   if (DesignatorList.empty())
     return false;
 
-  // Check for missing braces. If the types don't match then there are
-  // missing braces.
+  return enterImplicitInitLists(Init);
+}
+
+bool Designators::enterImplicitInitLists(const Expr *Init) {
+  // Check for missing braces by comparing the type of the last designator and
+  // type of Init.
   while (true) {
     const QualType T = DesignatorList.back().getType();
     // If the types match, there are no missing braces.
@@ -161,8 +175,8 @@ bool Designators::increment(const InitListExpr *ILE, const 
Expr *Init,
     // If the current type is an array, then get its first element.
     if (T->isArrayType()) {
       DesignatorList.push_back(
-          {Context.getAsArrayType(T)->getElementType(), 0,
-           Context.getAsConstantArrayType(T)->getSize().getZExtValue()});
+          {Context->getAsArrayType(T)->getElementType(), 0,
+           Context->getAsConstantArrayType(T)->getSize().getZExtValue()});
       continue;
     }
 
diff --git a/clang-tools-extra/clang-reorder-fields/Designator.h 
b/clang-tools-extra/clang-reorder-fields/Designator.h
index 66b74f2571110..f3e0cbbd959ca 100644
--- a/clang-tools-extra/clang-reorder-fields/Designator.h
+++ b/clang-tools-extra/clang-reorder-fields/Designator.h
@@ -115,15 +115,19 @@ class DesignatorIter {
 
 class Designators {
 public:
-  Designators() = default;
+  /// Initialize to the first member of the struct/array. Enters implicit
+  /// initializer lists until a type that matches Init is found.
+  Designators(const Expr *Init, const InitListExpr *ILE,
+              const ASTContext *Context);
+
+  /// Initialize to the designators of the given expression.
   Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
-              const ASTContext &Context);
+              const ASTContext *Context);
 
   /// Moves the designators to the next initializer in the struct/array. If the
   /// type of next initializer doesn't match the expected type then there are
   /// omitted braces and we add new designators to reflect that.
-  bool increment(const InitListExpr *ILE, const Expr *Init,
-                 const ASTContext &Context);
+  bool advanceToNextField(const Expr *Init);
 
   /// Gets a string representation from a list of designators. This string will
   /// be inserted before an initializer expression to make it designated.
@@ -136,6 +140,12 @@ class Designators {
   }
 
 private:
+  /// Enters any implicit initializer lists until a type that matches the given
+  /// expression is found.
+  bool enterImplicitInitLists(const Expr *Init);
+
+  const InitListExpr *ILE;
+  const ASTContext *Context;
   SmallVector<DesignatorIter, 1> DesignatorList;
 };
 
diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp 
b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
index 0c6841e298cc7..f7de3beeb6ca0 100644
--- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
+++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
@@ -92,11 +92,68 @@ struct ReorderedStruct {
       NewFieldsPositions[NewFieldsOrder[I]] = I;
   }
 
+  /// Compares compatible designators according to the new struct order.
+  /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0
+  /// if they are equal.
+  int operator()(const DesignatorIter &Lhs, const DesignatorIter &Rhs) const;
+
+  /// Compares compatible designator lists according to the new struct order.
+  /// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0
+  /// if they are equal.
+  int operator()(const Designators &Lhs, const Designators &Rhs) const;
+
   const RecordDecl *Definition;
   ArrayRef<unsigned> NewFieldsOrder;
   SmallVector<unsigned, 4> NewFieldsPositions;
 };
 
+int ReorderedStruct::operator()(const DesignatorIter &Lhs,
+                                const DesignatorIter &Rhs) const {
+  switch (Lhs.getTag()) {
+  case DesignatorIter::STRUCT:
+    assert(Rhs.getTag() == DesignatorIter::STRUCT &&
+           "Incompatible designators");
+    assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&
+           "Incompatible structs");
+    // Use the new layout for reordered struct.
+    if (Definition == Lhs.getStructDecl()) {
+      return NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] -
+             NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];
+    }
+    return Lhs.getStructIter()->getFieldIndex() -
+           Rhs.getStructIter()->getFieldIndex();
+  case DesignatorIter::ARRAY:
+  case DesignatorIter::ARRAY_RANGE:
+    // Array designators can be compared to array range designators.
+    assert((Rhs.getTag() == DesignatorIter::ARRAY ||
+            Rhs.getTag() == DesignatorIter::ARRAY_RANGE) &&
+           "Incompatible designators");
+    size_t LhsIdx = Lhs.getTag() == DesignatorIter::ARRAY
+                        ? Lhs.getArrayIndex()
+                        : Lhs.getArrayRangeStart();
+    size_t RhsIdx = Rhs.getTag() == DesignatorIter::ARRAY
+                        ? Rhs.getArrayIndex()
+                        : Rhs.getArrayRangeStart();
+    return LhsIdx - RhsIdx;
+  }
+  llvm_unreachable("Invalid designator tag");
+}
+
+int ReorderedStruct::operator()(const Designators &Lhs,
+                                const Designators &Rhs) const {
+  for (unsigned Idx = 0, Size = std::min(Lhs.size(), Rhs.size()); Idx < Size;
+       ++Idx) {
+    int DesignatorComp = (*this)(Lhs[Idx], Rhs[Idx]);
+    // If the current designators are not equal, return the result
+    if (DesignatorComp != 0)
+      return DesignatorComp;
+    // Otherwise, continue to the next pair.
+  }
+  // If all common designators were equal, compare the sizes of the designator
+  // lists.
+  return Lhs.size() - Rhs.size();
+}
+
 // FIXME: error-handling
 /// Replaces a range of source code by the specified text.
 static void
@@ -340,59 +397,6 @@ static bool isImplicitILE(const InitListExpr *ILE, const 
ASTContext &Context) {
   return false;
 }
 
-/// Compares compatible designators according to the new struct order.
-/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
-/// they are equal.
-static int cmpDesignators(const DesignatorIter &Lhs, const DesignatorIter &Rhs,
-                          const ReorderedStruct &Struct) {
-  switch (Lhs.getTag()) {
-  case DesignatorIter::STRUCT:
-    assert(Rhs.getTag() == DesignatorIter::STRUCT &&
-           "Incompatible designators");
-    assert(Lhs.getStructDecl() == Rhs.getStructDecl() &&
-           "Incompatible structs");
-    // Use the new layout for reordered struct.
-    if (Struct.Definition == Lhs.getStructDecl()) {
-      return Struct.NewFieldsPositions[Lhs.getStructIter()->getFieldIndex()] -
-             Struct.NewFieldsPositions[Rhs.getStructIter()->getFieldIndex()];
-    }
-    return Lhs.getStructIter()->getFieldIndex() -
-           Rhs.getStructIter()->getFieldIndex();
-  case DesignatorIter::ARRAY:
-  case DesignatorIter::ARRAY_RANGE:
-    // Array designators can be compared to array range designators.
-    assert((Rhs.getTag() == DesignatorIter::ARRAY ||
-            Rhs.getTag() == DesignatorIter::ARRAY_RANGE) &&
-           "Incompatible designators");
-    size_t LhsIdx = Lhs.getTag() == DesignatorIter::ARRAY
-                        ? Lhs.getArrayIndex()
-                        : Lhs.getArrayRangeStart();
-    size_t RhsIdx = Rhs.getTag() == DesignatorIter::ARRAY
-                        ? Rhs.getArrayIndex()
-                        : Rhs.getArrayRangeStart();
-    return LhsIdx - RhsIdx;
-  }
-  llvm_unreachable("Invalid designator tag");
-}
-
-/// Compares compatible designator lists according to the new struct order.
-/// Returns a negative value if Lhs < Rhs, positive value if Lhs > Rhs and 0 if
-/// they are equal.
-static int cmpDesignatorLists(const Designators &Lhs, const Designators &Rhs,
-                              const ReorderedStruct &Reorders) {
-  for (unsigned Idx = 0, Size = std::min(Lhs.size(), Rhs.size()); Idx < Size;
-       ++Idx) {
-    int DesignatorComp = cmpDesignators(Lhs[Idx], Rhs[Idx], Reorders);
-    // If the current designators are not equal, return the result
-    if (DesignatorComp != 0)
-      return DesignatorComp;
-    // Otherwise, continue to the next pair.
-  }
-  // If all common designators were equal, compare the sizes of the designator
-  // lists.
-  return Lhs.size() - Rhs.size();
-}
-
 /// Finds the semantic form of the first explicit ancestor of the given
 /// initializer list including itself.
 static const InitListExpr *getExplicitILE(const InitListExpr *ILE,
@@ -481,20 +485,32 @@ static bool reorderFieldsInInitListExpr(
     // Handle case when some fields are designated. Some fields can be
     // missing. Insert any missing designators and reorder the expressions
     // according to the new order.
-    Designators CurrentDesignators{};
+    std::optional<Designators> CurrentDesignators;
     // Remember each initializer expression along with its designators. They 
are
     // sorted later to determine the correct order.
     std::vector<std::pair<Designators, const Expr *>> Rewrites;
     for (const Expr *Init : SyntacticInitListEx->inits()) {
       if (const auto *DIE = dyn_cast_or_null<DesignatedInitExpr>(Init)) {
-        CurrentDesignators = {DIE, SyntacticInitListEx, Context};
+        CurrentDesignators.emplace(DIE, SyntacticInitListEx, &Context);
+        if (CurrentDesignators->size() == 0) {
+          llvm::errs() << "Initializer list with excess elements or "
+                          "non-constant size is not supported\n";
+          return false;
+        }
 
         // Use the child of the DesignatedInitExpr. This way designators are
         // always replaced.
-        Rewrites.push_back({CurrentDesignators, DIE->getInit()});
+        Rewrites.emplace_back(*CurrentDesignators, DIE->getInit());
       } else {
-        // Find the next field.
-        if (!CurrentDesignators.increment(SyntacticInitListEx, Init, Context)) 
{
+        // If designators are not initialized then initialize to the first
+        // field, otherwise move the next field.
+        if (!CurrentDesignators) {
+          CurrentDesignators.emplace(Init, SyntacticInitListEx, &Context);
+          if (CurrentDesignators->size() == 0) {
+            llvm::errs() << "Unsupported initializer list\n";
+            return false;
+          }
+        } else if (!CurrentDesignators->advanceToNextField(Init)) {
           llvm::errs() << "Unsupported initializer list\n";
           return false;
         }
@@ -502,13 +518,13 @@ static bool reorderFieldsInInitListExpr(
         // Do not rewrite implicit values. They just had to be processed to
         // find the correct designator.
         if (!isa<ImplicitValueInitExpr>(Init))
-          Rewrites.push_back({CurrentDesignators, Init});
+          Rewrites.emplace_back(*CurrentDesignators, Init);
       }
     }
 
     // Sort the designators according to the new order.
-    llvm::sort(Rewrites, [&RS](const auto &Lhs, const auto &Rhs) {
-      return cmpDesignatorLists(Lhs.first, Rhs.first, RS) < 0;
+    llvm::stable_sort(Rewrites, [&RS](const auto &Lhs, const auto &Rhs) {
+      return RS(Lhs.first, Rhs.first) < 0;
     });
 
     for (unsigned i = 0, e = Rewrites.size(); i < e; ++i) {

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to