================ @@ -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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits