-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[flang] Better renaming in module files #93106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
@llvm/pr-subscribers-flang-semantics Author: Peter Klausler (klausler) ChangesWhen 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. Patch is 22.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93106.diff 8 Files Affected:
diff --git a/flang/include/flang/Evaluate/constant.h b/flang/include/flang/Evaluate/constant.h
index 71be7906d2fe2..d9866a08889f3 100644
--- a/flang/include/flang/Evaluate/constant.h
+++ b/flang/include/flang/Evaluate/constant.h
@@ -126,8 +126,7 @@ class ConstantBase : public ConstantBounds {
constexpr Result result() const { return result_; }
constexpr DynamicType GetType() const { return result_.GetType(); }
- llvm::raw_ostream &AsFortran(llvm::raw_ostream &,
- const parser::CharBlock *derivedTypeRename = nullptr) const;
+ llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
protected:
std::vector<Element> Reshape(const ConstantSubscripts &) const;
diff --git a/flang/include/flang/Evaluate/expression.h b/flang/include/flang/Evaluate/expression.h
index 64db0b88d03e5..642ddf5116847 100644
--- a/flang/include/flang/Evaluate/expression.h
+++ b/flang/include/flang/Evaluate/expression.h
@@ -735,8 +735,7 @@ class StructureConstructor {
StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&);
int Rank() const { return 0; }
DynamicType GetType() const;
- llvm::raw_ostream &AsFortran(llvm::raw_ostream &,
- const parser::CharBlock *derivedTypeRename = nullptr) const;
+ llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
private:
std::optional<Expr<SomeType>> CreateParentComponent(const Symbol &) const;
diff --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h
index 93a0f21fa9145..de19e3d04dea8 100644
--- a/flang/include/flang/Evaluate/type.h
+++ b/flang/include/flang/Evaluate/type.h
@@ -272,9 +272,6 @@ const semantics::DerivedTypeSpec *GetDerivedTypeSpec(
const semantics::DerivedTypeSpec *GetParentTypeSpec(
const semantics::DerivedTypeSpec &);
-std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &,
- const parser::CharBlock *derivedTypeRename = nullptr);
-
template <TypeCategory CATEGORY, int KIND = 0> struct TypeBase {
static constexpr TypeCategory category{CATEGORY};
static constexpr int kind{KIND};
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 167e613816394..d382663762bc3 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -110,6 +110,9 @@ class SemanticsContext {
evaluate::FoldingContext &foldingContext() { return foldingContext_; }
parser::AllCookedSources &allCookedSources() { return allCookedSources_; }
ModuleDependences &moduleDependences() { return moduleDependences_; }
+ std::map<const Symbol *, SourceName> &moduleFileOutputRenamings() {
+ return moduleFileOutputRenamings_;
+ }
SemanticsContext &set_location(
const std::optional<parser::CharBlock> &location) {
@@ -299,6 +302,7 @@ class SemanticsContext {
std::list<parser::Program> modFileParseTrees_;
std::unique_ptr<CommonBlockMap> commonBlockMap_;
ModuleDependences moduleDependences_;
+ std::map<const Symbol *, SourceName> moduleFileOutputRenamings_;
};
class Semantics {
diff --git a/flang/lib/Evaluate/formatting.cpp b/flang/lib/Evaluate/formatting.cpp
index 20193b006bf2f..0870d56549f74 100644
--- a/flang/lib/Evaluate/formatting.cpp
+++ b/flang/lib/Evaluate/formatting.cpp
@@ -14,6 +14,7 @@
#include "flang/Evaluate/fold.h"
#include "flang/Evaluate/tools.h"
#include "flang/Parser/characters.h"
+#include "flang/Semantics/semantics.h"
#include "flang/Semantics/symbol.h"
#include "llvm/Support/raw_ostream.h"
@@ -53,7 +54,7 @@ static void ShapeAsFortran(llvm::raw_ostream &o,
template <typename RESULT, typename VALUE>
llvm::raw_ostream &ConstantBase<RESULT, VALUE>::AsFortran(
- llvm::raw_ostream &o, const parser::CharBlock *derivedTypeRename) const {
+ llvm::raw_ostream &o) const {
bool hasNonDefaultLowerBound{printLbounds && HasNonDefaultLowerBound()};
if (Rank() > 1 || hasNonDefaultLowerBound) {
o << "reshape(";
@@ -85,8 +86,7 @@ llvm::raw_ostream &ConstantBase<RESULT, VALUE>::AsFortran(
o << ".false." << '_' << Result::kind;
}
} else {
- StructureConstructor{result_.derivedTypeSpec(), value}.AsFortran(
- o, derivedTypeRename);
+ StructureConstructor{result_.derivedTypeSpec(), value}.AsFortran(o);
}
}
if (Rank() > 0) {
@@ -124,9 +124,89 @@ llvm::raw_ostream &Constant<Type<TypeCategory::Character, KIND>>::AsFortran(
return o;
}
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol,
+ std::optional<parser::CharBlock> name = std::nullopt) {
+ const auto &renamings{symbol.owner().context().moduleFileOutputRenamings()};
+ if (auto iter{renamings.find(&symbol)}; iter != renamings.end()) {
+ return o << iter->second.ToString();
+ } else if (name) {
+ return o << name->ToString();
+ } else {
+ return o << symbol.name().ToString();
+ }
+}
+
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::string &lit) {
+ return o << parser::QuoteCharacterLiteral(lit);
+}
+
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u16string &lit) {
+ return o << parser::QuoteCharacterLiteral(lit);
+}
+
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u32string &lit) {
+ return o << parser::QuoteCharacterLiteral(lit);
+}
+
+template <typename A>
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const A &x) {
+ return x.AsFortran(o);
+}
+
+template <typename A>
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, common::Reference<A> x) {
+ return EmitVar(o, *x);
+}
+
+template <typename A>
+llvm::raw_ostream &EmitVar(
+ llvm::raw_ostream &o, const A *p, const char *kw = nullptr) {
+ if (p) {
+ if (kw) {
+ o << kw;
+ }
+ EmitVar(o, *p);
+ }
+ return o;
+}
+
+template <typename A>
+llvm::raw_ostream &EmitVar(
+ llvm::raw_ostream &o, const std::optional<A> &x, const char *kw = nullptr) {
+ if (x) {
+ if (kw) {
+ o << kw;
+ }
+ EmitVar(o, *x);
+ }
+ return o;
+}
+
+template <typename A, bool COPY>
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o,
+ const common::Indirection<A, COPY> &p, const char *kw = nullptr) {
+ if (kw) {
+ o << kw;
+ }
+ EmitVar(o, p.value());
+ return o;
+}
+
+template <typename A>
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::shared_ptr<A> &p) {
+ CHECK(p);
+ return EmitVar(o, *p);
+}
+
+template <typename... A>
+llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::variant<A...> &u) {
+ common::visit([&](const auto &x) { EmitVar(o, x); }, u);
+ return o;
+}
+
llvm::raw_ostream &ActualArgument::AssumedType::AsFortran(
llvm::raw_ostream &o) const {
- return o << symbol_->name().ToString();
+ return EmitVar(o, *symbol_);
}
llvm::raw_ostream &ActualArgument::AsFortran(llvm::raw_ostream &o) const {
@@ -504,15 +584,37 @@ llvm::raw_ostream &ExpressionBase<RESULT>::AsFortran(
return o;
}
-llvm::raw_ostream &StructureConstructor::AsFortran(
- llvm::raw_ostream &o, const parser::CharBlock *derivedTypeRename) const {
- o << DerivedTypeSpecAsFortran(result_.derivedTypeSpec(), derivedTypeRename);
+static std::string DerivedTypeSpecAsFortran(
+ const semantics::DerivedTypeSpec &spec) {
+ std::string buf;
+ llvm::raw_string_ostream ss{buf};
+ EmitVar(ss, spec.typeSymbol(), spec.name());
+ char ch{'('};
+ for (const auto &[name, value] : spec.parameters()) {
+ ss << ch << name.ToString() << '=';
+ ch = ',';
+ if (value.isAssumed()) {
+ ss << '*';
+ } else if (value.isDeferred()) {
+ ss << ':';
+ } else {
+ value.GetExplicit()->AsFortran(ss);
+ }
+ }
+ if (ch != '(') {
+ ss << ')';
+ }
+ return ss.str();
+}
+
+llvm::raw_ostream &StructureConstructor::AsFortran(llvm::raw_ostream &o) const {
+ o << DerivedTypeSpecAsFortran(result_.derivedTypeSpec());
if (values_.empty()) {
o << '(';
} else {
char ch{'('};
for (const auto &[symbol, value] : values_) {
- value.value().AsFortran(o << ch << symbol->name().ToString() << '=');
+ value.value().AsFortran(EmitVar(o << ch, *symbol) << '=');
ch = ',';
}
}
@@ -568,101 +670,6 @@ std::string SomeDerived::AsFortran() const {
}
}
-std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &spec,
- const parser::CharBlock *derivedTypeRename) {
- std::string buf;
- llvm::raw_string_ostream ss{buf};
- ss << (derivedTypeRename ? *derivedTypeRename : spec.name()).ToString();
- char ch{'('};
- for (const auto &[name, value] : spec.parameters()) {
- ss << ch << name.ToString() << '=';
- ch = ',';
- if (value.isAssumed()) {
- ss << '*';
- } else if (value.isDeferred()) {
- ss << ':';
- } else {
- value.GetExplicit()->AsFortran(ss);
- }
- }
- if (ch != '(') {
- ss << ')';
- }
- return ss.str();
-}
-
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol) {
- return o << symbol.name().ToString();
-}
-
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::string &lit) {
- return o << parser::QuoteCharacterLiteral(lit);
-}
-
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u16string &lit) {
- return o << parser::QuoteCharacterLiteral(lit);
-}
-
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u32string &lit) {
- return o << parser::QuoteCharacterLiteral(lit);
-}
-
-template <typename A>
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const A &x) {
- return x.AsFortran(o);
-}
-
-template <typename A>
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, common::Reference<A> x) {
- return EmitVar(o, *x);
-}
-
-template <typename A>
-llvm::raw_ostream &EmitVar(
- llvm::raw_ostream &o, const A *p, const char *kw = nullptr) {
- if (p) {
- if (kw) {
- o << kw;
- }
- EmitVar(o, *p);
- }
- return o;
-}
-
-template <typename A>
-llvm::raw_ostream &EmitVar(
- llvm::raw_ostream &o, const std::optional<A> &x, const char *kw = nullptr) {
- if (x) {
- if (kw) {
- o << kw;
- }
- EmitVar(o, *x);
- }
- return o;
-}
-
-template <typename A, bool COPY>
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o,
- const common::Indirection<A, COPY> &p, const char *kw = nullptr) {
- if (kw) {
- o << kw;
- }
- EmitVar(o, p.value());
- return o;
-}
-
-template <typename A>
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::shared_ptr<A> &p) {
- CHECK(p);
- return EmitVar(o, *p);
-}
-
-template <typename... A>
-llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::variant<A...> &u) {
- common::visit([&](const auto &x) { EmitVar(o, x); }, u);
- return o;
-}
-
llvm::raw_ostream &BaseObject::AsFortran(llvm::raw_ostream &o) const {
return EmitVar(o, u);
}
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index bb8c6c7567b8d..67523c468f18d 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().typeSymb...
[truncated]
|
llvm#93106 introduced some necessary fixes to module file generation, but has also caused a regression. The module file output can include bogus attempts to USE-associate symbols local to derived type scopes, like components and bindings. Fix, and extend a test.
#93106 introduced some necessary fixes to module file generation, but has also caused a regression. The module file output can include bogus attempts to USE-associate symbols local to derived type scopes, like components and bindings. Fix, and extend a test.
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.