Skip to content

Commit 3a8f449

Browse files
committed
[flang] Safer hermetic module file reading
When a hermetic module file is read, use a new scope to hold its dependent modules so that they don't conflict with any modules in the global scope.
1 parent b0a4b5b commit 3a8f449

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

flang/docs/ModFiles.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,13 @@ a diagnostic but we still wouldn't have line numbers.
164164
To provide line numbers and character positions or source lines as the user
165165
wrote them we would have to save some amount of provenance information in the
166166
module file as well.
167+
168+
## Hermetic modules files
169+
170+
Top-level module files for libraries can be build with `-fhermetic-module-files`.
171+
This option causes these module files to contain copies of all of the non-intrinsic
172+
modules on which they depend, so that non-top-level local modules and the
173+
modules of dependent libraries need not also be packaged with the library.
174+
When the compiler reads a hermetic module file, the copies of the dependent
175+
modules are read into their own scope, and will not conflict with other modules
176+
of the same name that client code might `USE`.

flang/include/flang/Semantics/semantics.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ class SemanticsContext {
110110
}
111111
Scope &globalScope() { return globalScope_; }
112112
Scope &intrinsicModulesScope() { return intrinsicModulesScope_; }
113+
Scope *currentHermeticModuleFileScope() {
114+
return currentHermeticModuleFileScope_;
115+
}
116+
void set_currentHermeticModuleFileScope(Scope *scope) {
117+
currentHermeticModuleFileScope_ = scope;
118+
}
113119
parser::Messages &messages() { return messages_; }
114120
evaluate::FoldingContext &foldingContext() { return foldingContext_; }
115121
parser::AllCookedSources &allCookedSources() { return allCookedSources_; }
@@ -313,6 +319,7 @@ class SemanticsContext {
313319
evaluate::TargetCharacteristics targetCharacteristics_;
314320
Scope globalScope_;
315321
Scope &intrinsicModulesScope_;
322+
Scope *currentHermeticModuleFileScope_{nullptr};
316323
ScopeIndex scopeIndex_;
317324
parser::Messages messages_;
318325
evaluate::FoldingContext foldingContext_;

flang/lib/Semantics/mod-file.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,12 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
13661366
name.ToString(), isIntrinsic.value_or(false))};
13671367
if (!isIntrinsic.value_or(false) && !ancestor) {
13681368
// Already present in the symbol table as a usable non-intrinsic module?
1369+
if (Scope * hermeticScope{context_.currentHermeticModuleFileScope()}) {
1370+
auto it{hermeticScope->find(name)};
1371+
if (it != hermeticScope->end()) {
1372+
return it->second->scope();
1373+
}
1374+
}
13691375
auto it{context_.globalScope().find(name)};
13701376
if (it != context_.globalScope().end()) {
13711377
Scope *scope{it->second->scope()};
@@ -1543,9 +1549,22 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
15431549
// Process declarations from the module file
15441550
auto wasModuleFileName{context_.foldingContext().moduleFileName()};
15451551
context_.foldingContext().set_moduleFileName(name);
1552+
// Are there multiple modules in the module file due to it having been
1553+
// created under -fhermetic-module-files? If so, process them first in
1554+
// their own nested scope that will be visible only to USE statements
1555+
// within the module file.
1556+
if (parseTree.v.size() > 1) {
1557+
parser::Program hermeticModules{std::move(parseTree.v)};
1558+
parseTree.v.emplace_back(std::move(hermeticModules.v.front()));
1559+
hermeticModules.v.pop_front();
1560+
Scope &hermeticScope{topScope.MakeScope(Scope::Kind::Global)};
1561+
context_.set_currentHermeticModuleFileScope(&hermeticScope);
1562+
ResolveNames(context_, hermeticModules, hermeticScope);
1563+
}
15461564
GetModuleDependences(context_.moduleDependences(), sourceFile->content());
15471565
ResolveNames(context_, parseTree, topScope);
15481566
context_.foldingContext().set_moduleFileName(wasModuleFileName);
1567+
context_.set_currentHermeticModuleFileScope(nullptr);
15491568
if (!moduleSymbol) {
15501569
// Submodule symbols' storage are owned by their parents' scopes,
15511570
// but their names are not in their parents' dictionaries -- we

flang/lib/Semantics/resolve-names.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2548,9 +2548,11 @@ void ScopeHandler::PopScope() {
25482548
ConvertToObjectEntity(*pair.second);
25492549
}
25502550
funcResultStack_.Pop();
2551-
// If popping back into a global scope, pop back to the main global scope.
2552-
SetScope(currScope_->parent().IsGlobal() ? context().globalScope()
2553-
: currScope_->parent());
2551+
// If popping back into a global scope, pop back to the top scope.
2552+
Scope *hermetic{context().currentHermeticModuleFileScope()};
2553+
SetScope(currScope_->parent().IsGlobal()
2554+
? (hermetic ? *hermetic : context().globalScope())
2555+
: currScope_->parent());
25542556
}
25552557
void ScopeHandler::SetScope(Scope &scope) {
25562558
currScope_ = &scope;
@@ -9375,6 +9377,12 @@ template <typename A> std::set<SourceName> GetUses(const A &x) {
93759377
}
93769378

93779379
bool ResolveNamesVisitor::Pre(const parser::Program &x) {
9380+
if (Scope * hermetic{context().currentHermeticModuleFileScope()}) {
9381+
// Processing either the dependent modules or first module of a
9382+
// hermetic module file; ensure that the hermetic module scope has
9383+
// its implicit rules map entry.
9384+
ImplicitRulesVisitor::BeginScope(*hermetic);
9385+
}
93789386
std::map<SourceName, const parser::ProgramUnit *> modules;
93799387
std::set<SourceName> uses;
93809388
bool disordered{false};

0 commit comments

Comments
 (0)