Skip to content

Commit 5661188

Browse files
authored
[flang] Support multiple distinct module files with same name in one … (#84838)
…compilation Allow multiple module files with the same module name to exist in one compilation; distinct modules are distinguished by their hashes.
1 parent af61b8e commit 5661188

File tree

4 files changed

+46
-53
lines changed

4 files changed

+46
-53
lines changed

flang/include/flang/Semantics/module-dependences.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ class ModuleDependences {
2323
void AddDependence(
2424
std::string &&name, bool intrinsic, ModuleCheckSumType hash) {
2525
if (intrinsic) {
26-
intrinsicMap_.emplace(std::move(name), hash);
26+
intrinsicMap_.insert_or_assign(std::move(name), hash);
2727
} else {
28-
nonIntrinsicMap_.emplace(std::move(name), hash);
28+
nonIntrinsicMap_.insert_or_assign(std::move(name), hash);
2929
}
3030
}
3131
std::optional<ModuleCheckSumType> GetRequiredHash(

flang/include/flang/Semantics/symbol.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,15 @@ class ModuleDetails : public WithOmpDeclarative {
9191
return moduleFileHash_;
9292
}
9393
void set_moduleFileHash(ModuleCheckSumType x) { moduleFileHash_ = x; }
94+
const Symbol *previous() const { return previous_; }
95+
void set_previous(const Symbol *p) { previous_ = p; }
9496

9597
private:
9698
bool isSubmodule_;
9799
bool isDefaultPrivate_{false};
98100
const Scope *scope_{nullptr};
99101
std::optional<ModuleCheckSumType> moduleFileHash_;
102+
const Symbol *previous_{nullptr}; // same name, different module file hash
100103
};
101104

102105
class MainProgramDetails : public WithOmpDeclarative {

flang/lib/Semantics/mod-file.cpp

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,7 +1242,7 @@ static void GetModuleDependences(
12421242
std::size_t limit{content.size()};
12431243
std::string_view str{content.data(), limit};
12441244
for (std::size_t j{ModHeader::len};
1245-
str.substr(j, ModHeader::needLen) == ModHeader::need;) {
1245+
str.substr(j, ModHeader::needLen) == ModHeader::need; ++j) {
12461246
j += 7;
12471247
auto checkSum{ExtractCheckSum(str.substr(j, ModHeader::sumLen))};
12481248
if (!checkSum) {
@@ -1260,8 +1260,8 @@ static void GetModuleDependences(
12601260
for (; j < limit && str.at(j) != '\n'; ++j) {
12611261
}
12621262
if (j > start && j < limit && str.at(j) == '\n') {
1263-
dependences.AddDependence(
1264-
std::string{str.substr(start, j - start)}, intrinsic, *checkSum);
1263+
std::string depModName{str.substr(start, j - start)};
1264+
dependences.AddDependence(std::move(depModName), intrinsic, *checkSum);
12651265
} else {
12661266
break;
12671267
}
@@ -1271,7 +1271,7 @@ static void GetModuleDependences(
12711271
Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
12721272
Scope *ancestor, bool silent) {
12731273
std::string ancestorName; // empty for module
1274-
Symbol *notAModule{nullptr};
1274+
const Symbol *notAModule{nullptr};
12751275
bool fatalError{false};
12761276
if (ancestor) {
12771277
if (auto *scope{ancestor->FindSubmodule(name)}) {
@@ -1287,26 +1287,28 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
12871287
if (it != context_.globalScope().end()) {
12881288
Scope *scope{it->second->scope()};
12891289
if (scope->kind() == Scope::Kind::Module) {
1290-
if (requiredHash) {
1291-
if (const Symbol * foundModule{scope->symbol()}) {
1292-
if (const auto *module{foundModule->detailsIf<ModuleDetails>()};
1293-
module && module->moduleFileHash() &&
1294-
*requiredHash != *module->moduleFileHash()) {
1295-
Say(name, ancestorName,
1296-
"Multiple versions of the module '%s' cannot be required by the same compilation"_err_en_US,
1297-
name.ToString());
1298-
return nullptr;
1290+
for (const Symbol *found{scope->symbol()}; found;) {
1291+
if (const auto *module{found->detailsIf<ModuleDetails>()}) {
1292+
if (!requiredHash ||
1293+
*requiredHash ==
1294+
module->moduleFileHash().value_or(*requiredHash)) {
1295+
return const_cast<Scope *>(found->scope());
12991296
}
1297+
found = module->previous(); // same name, distinct hash
1298+
} else {
1299+
notAModule = found;
1300+
break;
13001301
}
13011302
}
1302-
return scope;
13031303
} else {
13041304
notAModule = scope->symbol();
1305-
// USE, NON_INTRINSIC global name isn't a module?
1306-
fatalError = isIntrinsic.has_value();
13071305
}
13081306
}
13091307
}
1308+
if (notAModule) {
1309+
// USE, NON_INTRINSIC global name isn't a module?
1310+
fatalError = isIntrinsic.has_value();
1311+
}
13101312
auto path{ModFileName(name, ancestorName, context_.moduleFileSuffix())};
13111313
parser::Parsing parsing{context_.allCookedSources()};
13121314
parser::Options options;
@@ -1360,42 +1362,18 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
13601362

13611363
// Look for the right module file if its hash is known
13621364
if (requiredHash && !fatalError) {
1363-
std::vector<std::string> misses;
13641365
for (const std::string &maybe :
13651366
parser::LocateSourceFileAll(path, options.searchDirectories)) {
13661367
if (const auto *srcFile{context_.allCookedSources().allSources().OpenPath(
13671368
maybe, llvm::errs())}) {
1368-
if (auto checkSum{VerifyHeader(srcFile->content())}) {
1369-
if (*checkSum == *requiredHash) {
1370-
path = maybe;
1371-
if (!misses.empty()) {
1372-
auto &msg{context_.Say(name,
1373-
"Module file for '%s' appears later in the module search path than conflicting modules with different checksums"_warn_en_US,
1374-
name.ToString())};
1375-
for (const std::string &m : misses) {
1376-
msg.Attach(
1377-
name, "Module file with a conflicting name: '%s'"_en_US, m);
1378-
}
1379-
}
1380-
misses.clear();
1381-
break;
1382-
} else {
1383-
misses.emplace_back(maybe);
1384-
}
1369+
if (auto checkSum{VerifyHeader(srcFile->content())};
1370+
checkSum && *checkSum == *requiredHash) {
1371+
path = maybe;
1372+
break;
13851373
}
13861374
}
13871375
}
1388-
if (!misses.empty()) {
1389-
auto &msg{Say(name, ancestorName,
1390-
"Could not find a module file for '%s' in the module search path with the expected checksum"_err_en_US,
1391-
name.ToString())};
1392-
for (const std::string &m : misses) {
1393-
msg.Attach(name, "Module file with different checksum: '%s'"_en_US, m);
1394-
}
1395-
return nullptr;
1396-
}
13971376
}
1398-
13991377
const auto *sourceFile{fatalError ? nullptr : parsing.Prescan(path, options)};
14001378
if (fatalError || parsing.messages().AnyFatalError()) {
14011379
if (!silent) {
@@ -1451,11 +1429,24 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
14511429
Scope &topScope{isIntrinsic.value_or(false) ? context_.intrinsicModulesScope()
14521430
: context_.globalScope()};
14531431
Symbol *moduleSymbol{nullptr};
1432+
const Symbol *previousModuleSymbol{nullptr};
14541433
if (!ancestor) { // module, not submodule
14551434
parentScope = &topScope;
14561435
auto pair{parentScope->try_emplace(name, UnknownDetails{})};
14571436
if (!pair.second) {
1458-
return nullptr;
1437+
// There is already a global symbol or intrinsic module of the same name.
1438+
previousModuleSymbol = &*pair.first->second;
1439+
if (const auto *details{
1440+
previousModuleSymbol->detailsIf<ModuleDetails>()}) {
1441+
if (!details->moduleFileHash().has_value()) {
1442+
return nullptr;
1443+
}
1444+
} else {
1445+
return nullptr;
1446+
}
1447+
CHECK(parentScope->erase(name) != 0);
1448+
pair = parentScope->try_emplace(name, UnknownDetails{});
1449+
CHECK(pair.second);
14591450
}
14601451
moduleSymbol = &*pair.first->second;
14611452
moduleSymbol->set(Symbol::Flag::ModFile);
@@ -1486,7 +1477,9 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
14861477
}
14871478
if (moduleSymbol) {
14881479
CHECK(moduleSymbol->test(Symbol::Flag::ModFile));
1489-
moduleSymbol->get<ModuleDetails>().set_moduleFileHash(checkSum.value());
1480+
auto &details{moduleSymbol->get<ModuleDetails>()};
1481+
details.set_moduleFileHash(checkSum.value());
1482+
details.set_previous(previousModuleSymbol);
14901483
if (isIntrinsic.value_or(false)) {
14911484
moduleSymbol->attrs().set(Attr::INTRINSIC);
14921485
}

flang/test/Semantics/modfile63.f90

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
! RUN: %flang_fc1 -fsyntax-only -I%S/Inputs/dir1 %s
22
! RUN: not %flang_fc1 -fsyntax-only -I%S/Inputs/dir2 %s 2>&1 | FileCheck --check-prefix=ERROR %s
33
! RUN: %flang_fc1 -Werror -fsyntax-only -I%S/Inputs/dir1 -I%S/Inputs/dir2 %s
4-
! RUN: not %flang_fc1 -Werror -fsyntax-only -I%S/Inputs/dir2 -I%S/Inputs/dir1 %s 2>&1 | FileCheck --check-prefix=WARNING %s
54

65
! Inputs/dir1 and Inputs/dir2 each have identical copies of modfile63b.mod.
76
! modfile63b.mod depends on Inputs/dir1/modfile63a.mod - the version in
8-
! Inputs/dir2/modfile63a.mod has a distinct checksum and should be
9-
! ignored with a warning.
7+
! Inputs/dir2/modfile63a.mod has a distinct checksum.
108

119
! If it becomes necessary to recompile those modules, just use the
1210
! module files as Fortran source.
@@ -15,5 +13,4 @@
1513
call s2
1614
end
1715

18-
! ERROR: Could not find a module file for 'modfile63a' in the module search path with the expected checksum
19-
! WARNING: Module file for 'modfile63a' appears later in the module search path than conflicting modules with different checksums
16+
! ERROR: Cannot read module file for module 'modfile63a': File is not the right module file for 'modfile63a':

0 commit comments

Comments
 (0)