Skip to content

Commit 038b42b

Browse files
authored
[flang] Safer hermetic module file reading (#121002)
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 c3a0fcc commit 038b42b

File tree

11 files changed

+346
-33
lines changed

11 files changed

+346
-33
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/Common/Fortran-features.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
7373
PreviousScalarUse, RedeclaredInaccessibleComponent, ImplicitShared,
7474
IndexVarRedefinition, IncompatibleImplicitInterfaces, BadTypeForTarget,
7575
VectorSubscriptFinalization, UndefinedFunctionResult, UselessIomsg,
76-
MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation)
76+
MismatchingDummyProcedure, SubscriptedEmptyArray, UnsignedLiteralTruncation,
77+
CompatibleDeclarationsFromDistinctModules)
7778

7879
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
7980
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;

flang/include/flang/Evaluate/type.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,8 @@ bool AreSameDerivedType(
510510
const semantics::DerivedTypeSpec &, const semantics::DerivedTypeSpec &);
511511
bool AreSameDerivedTypeIgnoringTypeParameters(
512512
const semantics::DerivedTypeSpec &, const semantics::DerivedTypeSpec &);
513+
bool AreSameDerivedTypeIgnoringSequence(
514+
const semantics::DerivedTypeSpec &, const semantics::DerivedTypeSpec &);
513515

514516
// For generating "[extern] template class", &c. boilerplate
515517
#define EXPAND_FOR_EACH_INTEGER_KIND(M, P, S) \

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/include/flang/Semantics/symbol.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,12 +605,12 @@ class UseDetails {
605605
class UseErrorDetails {
606606
public:
607607
UseErrorDetails(const UseDetails &);
608-
UseErrorDetails &add_occurrence(const SourceName &, const Scope &);
609-
using listType = std::list<std::pair<SourceName, const Scope *>>;
610-
const listType occurrences() const { return occurrences_; };
608+
UseErrorDetails &add_occurrence(const SourceName &, const Symbol &);
609+
using ListType = std::list<std::pair<SourceName, const Symbol *>>;
610+
const ListType occurrences() const { return occurrences_; };
611611

612612
private:
613-
listType occurrences_;
613+
ListType occurrences_;
614614
};
615615

616616
// A symbol host-associated from an enclosing scope.

flang/lib/Evaluate/type.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,13 @@ using SetOfDerivedTypePairs =
293293

294294
static bool AreSameDerivedType(const semantics::DerivedTypeSpec &,
295295
const semantics::DerivedTypeSpec &, bool ignoreTypeParameterValues,
296-
bool ignoreLenParameters, SetOfDerivedTypePairs &inProgress);
296+
bool ignoreLenParameters, bool ignoreSequence,
297+
SetOfDerivedTypePairs &inProgress);
297298

298299
// F2023 7.5.3.2
299300
static bool AreSameComponent(const semantics::Symbol &x,
300-
const semantics::Symbol &y, SetOfDerivedTypePairs &inProgress) {
301+
const semantics::Symbol &y, bool ignoreSequence,
302+
SetOfDerivedTypePairs &inProgress) {
301303
if (x.attrs() != y.attrs()) {
302304
return false;
303305
}
@@ -325,7 +327,8 @@ static bool AreSameComponent(const semantics::Symbol &x,
325327
!yType->IsUnlimitedPolymorphic() ||
326328
(!xType->IsUnlimitedPolymorphic() &&
327329
!AreSameDerivedType(xType->GetDerivedTypeSpec(),
328-
yType->GetDerivedTypeSpec(), false, false, inProgress))) {
330+
yType->GetDerivedTypeSpec(), false, false, ignoreSequence,
331+
inProgress))) {
329332
return false;
330333
}
331334
} else if (!xType->IsTkLenCompatibleWith(*yType)) {
@@ -449,7 +452,8 @@ static bool AreTypeParamCompatible(const semantics::DerivedTypeSpec &x,
449452
// F2023 7.5.3.2
450453
static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
451454
const semantics::DerivedTypeSpec &y, bool ignoreTypeParameterValues,
452-
bool ignoreLenParameters, SetOfDerivedTypePairs &inProgress) {
455+
bool ignoreLenParameters, bool ignoreSequence,
456+
SetOfDerivedTypePairs &inProgress) {
453457
if (&x == &y) {
454458
return true;
455459
}
@@ -472,7 +476,12 @@ static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
472476
inProgress.insert(thisQuery);
473477
const auto &xDetails{xSymbol.get<semantics::DerivedTypeDetails>()};
474478
const auto &yDetails{ySymbol.get<semantics::DerivedTypeDetails>()};
475-
if (!(xDetails.sequence() && yDetails.sequence()) &&
479+
if (xDetails.sequence() != yDetails.sequence() ||
480+
xSymbol.attrs().test(semantics::Attr::BIND_C) !=
481+
ySymbol.attrs().test(semantics::Attr::BIND_C)) {
482+
return false;
483+
}
484+
if (!ignoreSequence && !(xDetails.sequence() && yDetails.sequence()) &&
476485
!(xSymbol.attrs().test(semantics::Attr::BIND_C) &&
477486
ySymbol.attrs().test(semantics::Attr::BIND_C))) {
478487
// PGI does not enforce this requirement; all other Fortran
@@ -493,7 +502,8 @@ static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
493502
const auto yLookup{ySymbol.scope()->find(*yComponentName)};
494503
if (xLookup == xSymbol.scope()->end() ||
495504
yLookup == ySymbol.scope()->end() ||
496-
!AreSameComponent(*xLookup->second, *yLookup->second, inProgress)) {
505+
!AreSameComponent(
506+
*xLookup->second, *yLookup->second, ignoreSequence, inProgress)) {
497507
return false;
498508
}
499509
}
@@ -503,13 +513,19 @@ static bool AreSameDerivedType(const semantics::DerivedTypeSpec &x,
503513
bool AreSameDerivedType(
504514
const semantics::DerivedTypeSpec &x, const semantics::DerivedTypeSpec &y) {
505515
SetOfDerivedTypePairs inProgress;
506-
return AreSameDerivedType(x, y, false, false, inProgress);
516+
return AreSameDerivedType(x, y, false, false, false, inProgress);
507517
}
508518

509519
bool AreSameDerivedTypeIgnoringTypeParameters(
510520
const semantics::DerivedTypeSpec &x, const semantics::DerivedTypeSpec &y) {
511521
SetOfDerivedTypePairs inProgress;
512-
return AreSameDerivedType(x, y, true, true, inProgress);
522+
return AreSameDerivedType(x, y, true, true, false, inProgress);
523+
}
524+
525+
bool AreSameDerivedTypeIgnoringSequence(
526+
const semantics::DerivedTypeSpec &x, const semantics::DerivedTypeSpec &y) {
527+
SetOfDerivedTypePairs inProgress;
528+
return AreSameDerivedType(x, y, false, false, true, inProgress);
513529
}
514530

515531
static bool AreSameDerivedType(
@@ -536,7 +552,7 @@ static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x,
536552
} else {
537553
SetOfDerivedTypePairs inProgress;
538554
if (AreSameDerivedType(*x, *y, ignoreTypeParameterValues,
539-
ignoreLenTypeParameters, inProgress)) {
555+
ignoreLenTypeParameters, false, inProgress)) {
540556
return true;
541557
} else {
542558
return isPolymorphic &&

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()};
@@ -1544,9 +1550,22 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
15441550
// Process declarations from the module file
15451551
auto wasModuleFileName{context_.foldingContext().moduleFileName()};
15461552
context_.foldingContext().set_moduleFileName(name);
1553+
// Are there multiple modules in the module file due to it having been
1554+
// created under -fhermetic-module-files? If so, process them first in
1555+
// their own nested scope that will be visible only to USE statements
1556+
// within the module file.
1557+
if (parseTree.v.size() > 1) {
1558+
parser::Program hermeticModules{std::move(parseTree.v)};
1559+
parseTree.v.emplace_back(std::move(hermeticModules.v.front()));
1560+
hermeticModules.v.pop_front();
1561+
Scope &hermeticScope{topScope.MakeScope(Scope::Kind::Global)};
1562+
context_.set_currentHermeticModuleFileScope(&hermeticScope);
1563+
ResolveNames(context_, hermeticModules, hermeticScope);
1564+
}
15471565
GetModuleDependences(context_.moduleDependences(), sourceFile->content());
15481566
ResolveNames(context_, parseTree, topScope);
15491567
context_.foldingContext().set_moduleFileName(wasModuleFileName);
1568+
context_.set_currentHermeticModuleFileScope(nullptr);
15501569
if (!moduleSymbol) {
15511570
// Submodule symbols' storage are owned by their parents' scopes,
15521571
// but their names are not in their parents' dictionaries -- we

0 commit comments

Comments
 (0)