diff options
author | Peter Klausler <35819229+klausler@users.noreply.github.com> | 2024-05-23 16:20:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-23 16:20:51 -0700 |
commit | 9ce8e63ceb447f7c2a0e92595466ed13a5acac48 (patch) | |
tree | 66d0093b3091b9d3d470b44a5facb4d7afa0f485 /flang/lib/Semantics/mod-file.cpp | |
parent | 47b485c052d3ced9d846cf0e9b6a1a7d450f6dee (diff) | |
download | llvm-9ce8e63ceb447f7c2a0e92595466ed13a5acac48.zip llvm-9ce8e63ceb447f7c2a0e92595466ed13a5acac48.tar.gz llvm-9ce8e63ceb447f7c2a0e92595466ed13a5acac48.tar.bz2 |
[flang] Better renaming in module files (#93106)
When a symbol from one module is used in another without an explicit USE
association, the module file output code may need to use another name
for it -- either with a name that is already available via USE
association with renaming, or by means of a new private USE association,
possibly with renaming to avoid a clash.
Module file output was dealing properly with names of derived types, but
wasn't accounting for symbols that appear in expressions other than
initializations. This was specifically a problem with an application
module that had a call to a NOPASS type-bound procedure in an array
bound specification expression, which semantics had resolved to the name
of a private module function.
This patch implements renaming, when necessary, for all symbols
appearing in expressions and type names, and replaces the previous
implementation of derived type renaming. It also gets a little smarter
about avoiding the creation of compiler-generated names when a name from
another module has been brought into scope already by means of USE
association with renaming.
Diffstat (limited to 'flang/lib/Semantics/mod-file.cpp')
-rw-r--r-- | flang/lib/Semantics/mod-file.cpp | 153 |
1 files changed, 98 insertions, 55 deletions
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp index bb8c6c7..67523c4 100644 --- a/flang/lib/Semantics/mod-file.cpp +++ b/flang/lib/Semantics/mod-file.cpp @@ -46,11 +46,11 @@ struct ModHeader { }; static std::optional<SourceName> GetSubmoduleParent(const parser::Program &); -static void CollectSymbols(const Scope &, SymbolVector &, SymbolVector &, - std::map<const Symbol *, SourceName> &, UnorderedSymbolSet &); +static void CollectSymbols( + const Scope &, SymbolVector &, SymbolVector &, UnorderedSymbolSet &); static void PutPassName(llvm::raw_ostream &, const std::optional<SourceName> &); static void PutInit(llvm::raw_ostream &, const Symbol &, const MaybeExpr &, - const parser::Expr *, const std::map<const Symbol *, SourceName> &); + const parser::Expr *); static void PutInit(llvm::raw_ostream &, const MaybeIntExpr &); static void PutBound(llvm::raw_ostream &, const Bound &); static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &); @@ -200,47 +200,102 @@ std::string ModFileWriter::GetAsString(const Symbol &symbol) { return all.str(); } -// Collect symbols from initializations that are being referenced directly -// from other modules; they may require new USE associations. -static void HarvestInitializerSymbols( - SourceOrderedSymbolSet &set, const Scope &scope) { - for (const auto &[_, symbol] : scope) { - if (symbol->has<DerivedTypeDetails>()) { - if (symbol->scope()) { - HarvestInitializerSymbols(set, *symbol->scope()); +// Collect symbols from constant and specification expressions that are being +// referenced directly from other modules; they may require new USE +// associations. +static void HarvestSymbolsNeededFromOtherModules( + SourceOrderedSymbolSet &, const Scope &); +static void HarvestSymbolsNeededFromOtherModules( + SourceOrderedSymbolSet &set, const Symbol &symbol, const Scope &scope) { + auto HarvestBound{[&](const Bound &bound) { + if (const auto &expr{bound.GetExplicit()}) { + for (SymbolRef ref : evaluate::CollectSymbols(*expr)) { + set.emplace(*ref); } - } else if (const auto &generic{symbol->detailsIf<GenericDetails>()}; - generic && generic->derivedType()) { - const Symbol &dtSym{*generic->derivedType()}; - if (dtSym.has<DerivedTypeDetails>()) { - if (dtSym.scope()) { - HarvestInitializerSymbols(set, *dtSym.scope()); - } - } else { - CHECK(dtSym.has<UseDetails>() || dtSym.has<UseErrorDetails>()); + } + }}; + auto HarvestShapeSpec{[&](const ShapeSpec &shapeSpec) { + HarvestBound(shapeSpec.lbound()); + HarvestBound(shapeSpec.ubound()); + }}; + auto HarvestArraySpec{[&](const ArraySpec &arraySpec) { + for (const auto &shapeSpec : arraySpec) { + HarvestShapeSpec(shapeSpec); + } + }}; + + if (symbol.has<DerivedTypeDetails>()) { + if (symbol.scope()) { + HarvestSymbolsNeededFromOtherModules(set, *symbol.scope()); + } + } else if (const auto &generic{symbol.detailsIf<GenericDetails>()}; + generic && generic->derivedType()) { + const Symbol &dtSym{*generic->derivedType()}; + if (dtSym.has<DerivedTypeDetails>()) { + if (dtSym.scope()) { + HarvestSymbolsNeededFromOtherModules(set, *dtSym.scope()); } - } else if (IsNamedConstant(*symbol) || scope.IsDerivedType()) { - if (const auto *object{symbol->detailsIf<ObjectEntityDetails>()}) { - if (object->init()) { - for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) { - set.emplace(*ref); - } - } - } else if (const auto *proc{symbol->detailsIf<ProcEntityDetails>()}) { - if (proc->init() && *proc->init()) { - set.emplace(**proc->init()); + } else { + CHECK(dtSym.has<UseDetails>() || dtSym.has<UseErrorDetails>()); + } + } else if (const auto *object{symbol.detailsIf<ObjectEntityDetails>()}) { + HarvestArraySpec(object->shape()); + HarvestArraySpec(object->coshape()); + if (IsNamedConstant(symbol) || scope.IsDerivedType()) { + if (object->init()) { + for (SymbolRef ref : evaluate::CollectSymbols(*object->init())) { + set.emplace(*ref); } } } + } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) { + if (proc->init() && *proc->init() && scope.IsDerivedType()) { + set.emplace(**proc->init()); + } + } else if (const auto *subp{symbol.detailsIf<SubprogramDetails>()}) { + for (const Symbol *dummy : subp->dummyArgs()) { + if (dummy) { + HarvestSymbolsNeededFromOtherModules(set, *dummy, scope); + } + } + if (subp->isFunction()) { + HarvestSymbolsNeededFromOtherModules(set, subp->result(), scope); + } + } +} + +static void HarvestSymbolsNeededFromOtherModules( + SourceOrderedSymbolSet &set, const Scope &scope) { + for (const auto &[_, symbol] : scope) { + HarvestSymbolsNeededFromOtherModules(set, *symbol, scope); } } void ModFileWriter::PrepareRenamings(const Scope &scope) { - SourceOrderedSymbolSet symbolsInInits; - HarvestInitializerSymbols(symbolsInInits, scope); - for (SymbolRef s : symbolsInInits) { + // Identify use-associated symbols already in scope under some name + std::map<const Symbol *, const Symbol *> useMap; + for (const auto &[name, symbolRef] : scope) { + const Symbol *symbol{&*symbolRef}; + while (const auto *hostAssoc{symbol->detailsIf<HostAssocDetails>()}) { + symbol = &hostAssoc->symbol(); + } + if (const auto *use{symbol->detailsIf<UseDetails>()}) { + useMap.emplace(&use->symbol(), symbol); + } + } + // Collect symbols needed from other modules + SourceOrderedSymbolSet symbolsNeeded; + HarvestSymbolsNeededFromOtherModules(symbolsNeeded, scope); + // Establish any necessary renamings of symbols in other modules + // to their names in this scope, creating those new names when needed. + auto &renamings{context_.moduleFileOutputRenamings()}; + for (SymbolRef s : symbolsNeeded) { const Scope *sMod{FindModuleContaining(s->owner())}; - if (!sMod) { + if (!sMod || sMod == &scope) { + continue; + } + if (auto iter{useMap.find(&*s)}; iter != useMap.end()) { + renamings.emplace(&*s, iter->second->name()); continue; } SourceName rename{s->name()}; @@ -272,10 +327,10 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) { uses_ << DEREF(sMod->symbol()).name() << ",only:"; if (rename != s->name()) { uses_ << rename << "=>"; + renamings.emplace(&*s, rename); } uses_ << s->name() << '\n'; useExtraAttrs_ << "private::" << rename << '\n'; - renamings_.emplace(&*s, rename); } } @@ -283,9 +338,11 @@ void ModFileWriter::PrepareRenamings(const Scope &scope) { void ModFileWriter::PutSymbols(const Scope &scope) { SymbolVector sorted; SymbolVector uses; + auto &renamings{context_.moduleFileOutputRenamings()}; + auto previousRenamings{std::move(renamings)}; PrepareRenamings(scope); UnorderedSymbolSet modules; - CollectSymbols(scope, sorted, uses, renamings_, modules); + CollectSymbols(scope, sorted, uses, modules); // Write module files for dependencies first so that their // hashes are known. for (auto ref : modules) { @@ -318,6 +375,7 @@ void ModFileWriter::PutSymbols(const Scope &scope) { } } CHECK(typeBindings.str().empty()); + renamings = std::move(previousRenamings); } // Emit components in order @@ -521,7 +579,7 @@ void ModFileWriter::PutDECStructure( } decls_ << ref->name(); PutShape(decls_, object->shape(), '(', ')'); - PutInit(decls_, *ref, object->init(), nullptr, renamings_); + PutInit(decls_, *ref, object->init(), nullptr); emittedDECFields_.insert(*ref); } else if (any) { break; // any later use of this structure will use RECORD/str/ @@ -767,8 +825,7 @@ static inline SourceName NameInModuleFile(const Symbol &symbol) { // Collect the symbols of this scope sorted by their original order, not name. // Generics and namelists are exceptions: they are sorted after other symbols. void CollectSymbols(const Scope &scope, SymbolVector &sorted, - SymbolVector &uses, std::map<const Symbol *, SourceName> &renamings, - UnorderedSymbolSet &modules) { + SymbolVector &uses, UnorderedSymbolSet &modules) { SymbolVector namelist, generics; auto symbols{scope.GetSymbols()}; std::size_t commonSize{scope.commonBlocks().size()}; @@ -878,8 +935,7 @@ void ModFileWriter::PutObjectEntity( getSymbolAttrsToWrite(symbol)); PutShape(os, details.shape(), '(', ')'); PutShape(os, details.coshape(), '[', ']'); - PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit(), - renamings_); + PutInit(os, symbol, details.init(), details.unanalyzedPDTComponentInit()); os << '\n'; if (auto tkr{GetIgnoreTKR(symbol)}; !tkr.empty()) { os << "!dir$ ignore_tkr("; @@ -973,25 +1029,12 @@ void ModFileWriter::PutTypeParam(llvm::raw_ostream &os, const Symbol &symbol) { } void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init, - const parser::Expr *unanalyzed, - const std::map<const Symbol *, SourceName> &renamings) { + const parser::Expr *unanalyzed) { if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) { const char *assign{symbol.attrs().test(Attr::POINTER) ? "=>" : "="}; if (unanalyzed) { parser::Unparse(os << assign, *unanalyzed); } else if (init) { - if (const auto *dtConst{ - evaluate::UnwrapExpr<evaluate::Constant<evaluate::SomeDerived>>( - *init)}) { - const Symbol &dtSym{dtConst->result().derivedTypeSpec().typeSymbol()}; - if (auto iter{renamings.find(&dtSym)}; iter != renamings.end()) { - // Initializer is a constant whose derived type's name has - // been brought into scope from a module under a new name - // to avoid a conflict. - dtConst->AsFortran(os << assign, &iter->second); - return; - } - } init->AsFortran(os << assign); } } |