================
@@ -289,35 +321,215 @@ 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.
/// \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.
- // 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() != 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};
----------------
alexander-shaposhnikov wrote:
yeah, looks good, thanks!
https://github.com/llvm/llvm-project/pull/142150
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits