aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Semantics/mod-file.cpp
diff options
context:
space:
mode:
authorPeter Klausler <35819229+klausler@users.noreply.github.com>2024-05-23 16:20:51 -0700
committerGitHub <noreply@github.com>2024-05-23 16:20:51 -0700
commit9ce8e63ceb447f7c2a0e92595466ed13a5acac48 (patch)
tree66d0093b3091b9d3d470b44a5facb4d7afa0f485 /flang/lib/Semantics/mod-file.cpp
parent47b485c052d3ced9d846cf0e9b6a1a7d450f6dee (diff)
downloadllvm-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.cpp153
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);
}
}