[flang-commits] [flang] 43e98b2 - [flang] Do not implicitly use module when processing the module (#208582)
via flang-commits
flang-commits at lists.llvm.org
Thu Jul 9 20:21:00 PDT 2026
Author: Valentin Clement (バレンタイン クレメン)
Date: 2026-07-09T20:20:55-07:00
New Revision: 43e98b2e08ec8d012e4aa442392c1d204650d471
URL: https://github.com/llvm/llvm-project/commit/43e98b2e08ec8d012e4aa442392c1d204650d471
DIFF: https://github.com/llvm/llvm-project/commit/43e98b2e08ec8d012e4aa442392c1d204650d471.diff
LOG: [flang] Do not implicitly use module when processing the module (#208582)
https://github.com/llvm/llvm-project/pull/207824 Added ability to use
implicitly a module. The use should not happen while processing the
module used implicitly.
Added:
Modified:
flang/lib/Semantics/resolve-names.cpp
flang/test/Driver/bbc-implicit-use-module.f90
flang/tools/bbc/bbc.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 6079cfced9151..5a92cfd738ef4 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -833,6 +833,10 @@ class ModuleVisitor : public virtual ScopeHandler {
nonIntrinsicUses_.clear();
}
+protected:
+ std::optional<std::string> implicitUseModuleBeingResolved_;
+ std::set<std::string> implicitUseModulesInCurrentProgram_;
+
private:
// The location of the last AccessStmt without access-ids, if any.
std::optional<SourceName> prevAccessStmt_;
@@ -3916,16 +3920,44 @@ void ModuleVisitor::AddUseForCommonBlocks() {
}
void ModuleVisitor::AddImplicitUseModules() {
+ if (InModuleFile() || currScope().kind() != Scope::Kind::Subprogram) {
+ return;
+ }
for (const std::string &module : context().implicitUseModules()) {
if (module.empty()) {
continue;
}
SourceName moduleName{module};
- std::optional<SourceName> currModuleName{currScope().GetName()};
- if (currScope().IsModule() && currModuleName &&
- *currModuleName == moduleName) {
+ if (implicitUseModulesInCurrentProgram_.count(module) != 0) {
+ continue;
+ }
+ if (implicitUseModuleBeingResolved_ &&
+ *implicitUseModuleBeingResolved_ == module) {
+ continue;
+ }
+ bool isContainedInImplicitModule{false};
+ for (const Scope *scope{&currScope()}; !scope->IsTopLevel();
+ scope = &scope->parent()) {
+ if (scope->kind() == Scope::Kind::Module) {
+ if (std::optional<SourceName> scopeName{scope->GetName()};
+ scopeName && scopeName->ToString() == module) {
+ // Do not implicitly USE a module while resolving anything contained
+ // in that module; doing so would be a self USE.
+ isContainedInImplicitModule = true;
+ break;
+ }
+ }
+ }
+ if (isContainedInImplicitModule) {
continue;
}
+ if (auto it{context().globalScope().find(moduleName)};
+ it != context().globalScope().end()) {
+ if (Scope *scope{it->second->scope()};
+ scope && DoesScopeContain(scope, currScope())) {
+ continue;
+ }
+ }
parser::Name name{moduleName};
std::optional<bool> isIntrinsic;
if (currScope().IsModule() && currScope().symbol() &&
@@ -11007,6 +11039,10 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
return false;
}
ProgramTree &root{ProgramTree::Build(x, context())};
+ auto implicitUseModuleBeingResolvedRestorer{
+ common::ScopedSet(implicitUseModuleBeingResolved_,
+ root.IsModule() ? std::optional<std::string>{root.name().ToString()}
+ : implicitUseModuleBeingResolved_)};
SetScope(topScope_);
ResolveSpecificationParts(root);
FinishSpecificationParts(root);
@@ -11048,6 +11084,7 @@ bool ResolveNamesVisitor::Pre(const parser::Program &x) {
ImplicitRulesVisitor::BeginScope(*hermetic);
}
std::map<SourceName, const parser::ProgramUnit *> modules;
+ std::set<std::string> moduleNamesInCurrentProgram;
std::set<SourceName> uses;
bool disordered{false};
for (const auto &progUnit : x.v) {
@@ -11057,6 +11094,7 @@ bool ResolveNamesVisitor::Pre(const parser::Program &x) {
const auto &moduleStmt{
std::get<parser::Statement<parser::ModuleStmt>>(mod.t)};
const SourceName &name{moduleStmt.statement.v.source};
+ moduleNamesInCurrentProgram.insert(name.ToString());
if (auto iter{modules.find(name)}; iter != modules.end()) {
Say(name,
"Module '%s' appears multiple times in a compilation unit"_err_en_US)
@@ -11080,6 +11118,7 @@ bool ResolveNamesVisitor::Pre(const parser::Program &x) {
uses.insert(used);
}
}
+ implicitUseModulesInCurrentProgram_ = std::move(moduleNamesInCurrentProgram);
if (!disordered) {
return true;
}
@@ -11174,6 +11213,10 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
if (node.isSpecificationPartResolved()) {
return; // been here already
}
+ auto implicitUseModuleBeingResolvedRestorer{
+ common::ScopedSet(implicitUseModuleBeingResolved_,
+ node.IsModule() ? std::optional<std::string>{node.name().ToString()}
+ : implicitUseModuleBeingResolved_)};
node.set_isSpecificationPartResolved();
if (!BeginScopeForNode(node)) {
return; // an error prevented scope from being created
diff --git a/flang/test/Driver/bbc-implicit-use-module.f90 b/flang/test/Driver/bbc-implicit-use-module.f90
index 733ad69580c1c..c7c1af9b64231 100644
--- a/flang/test/Driver/bbc-implicit-use-module.f90
+++ b/flang/test/Driver/bbc-implicit-use-module.f90
@@ -1,7 +1,10 @@
! Test bbc's test-only implicit USE module hook.
! RUN: split-file %s %t
+! RUN: mkdir -p %t/self
+! RUN: bbc -module %t/self -implicit-use-module implicit_mod %t/implicit_mod.f90 -o /dev/null
! RUN: bbc -module %t %t/implicit_mod.f90 -o /dev/null
+! RUN: not bbc -emit-hlfir -I %t -implicit-use-module implicit_mod %t/use_in_module.f90 -o - 2>&1 | FileCheck %s --check-prefix=MODULE-SCOPE
! RUN: bbc -emit-hlfir -fopenacc -I %t -implicit-use-module implicit_mod %t/use_implicit.f90 -o - | FileCheck %s
!--- implicit_mod.f90
@@ -10,17 +13,30 @@ module implicit_mod
integer :: common_value
integer :: module_value = 42
common /implicit_common/ common_value
+contains
+ subroutine contained
+ integer :: x
+ x = module_value
+ end subroutine
end module
!--- use_implicit.f90
subroutine use_implicit
- integer :: x
+ real :: x
!$acc data copy(/implicit_common/)
x = module_value + common_value
!$acc end data
end subroutine
+!--- use_in_module.f90
+module use_in_module
+ implicit none
+ integer :: x = module_value
+end module
+
+! MODULE-SCOPE: No explicit type declared for 'module_value'
+
! CHECK-LABEL: func.func @_QPuse_implicit()
! CHECK-DAG: fir.address_of(@_QMimplicit_modEmodule_value) : !fir.ref<i32>
! CHECK-DAG: %[[COMMON:.*]] = fir.address_of(@implicit_common_) : !fir.ref<!fir.array<4xi8>>
-! CHECK-DAG: acc.copyin varPtr(%[[COMMON]]
+! CHECK-DAG: acc.copyin varPtr(%[[COMMON]] : !fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<4xi8>> {dataClause = #acc<data_clause acc_copy>, name = "implicit_common"}
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 88fa43c748e2f..124c566bc6b13 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -428,6 +428,27 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
// run semantics
auto &parseTree = *parsing.parseTree();
+ std::vector<std::string> implicitUseModuleNames;
+ for (const std::string &module : implicitUseModules) {
+ bool moduleIsDefinedInInput{false};
+ for (const Fortran::parser::ProgramUnit &unit : parseTree.v) {
+ if (const auto *indirectModule{std::get_if<
+ Fortran::common::Indirection<Fortran::parser::Module>>(
+ &unit.u)}) {
+ const auto &moduleStmt{
+ std::get<Fortran::parser::Statement<Fortran::parser::ModuleStmt>>(
+ indirectModule->value().t)};
+ if (moduleStmt.statement.v.source.ToString() == module) {
+ moduleIsDefinedInInput = true;
+ break;
+ }
+ }
+ }
+ if (!moduleIsDefinedInInput) {
+ implicitUseModuleNames.push_back(module);
+ }
+ }
+ semanticsContext.set_implicitUseModules(implicitUseModuleNames);
Fortran::semantics::Semantics semantics(semanticsContext, parseTree);
semantics.Perform();
semantics.EmitMessages(llvm::errs());
@@ -695,7 +716,6 @@ int main(int argc, char **argv) {
.set_moduleFileSuffix(moduleSuffix)
.set_searchDirectories(includeDirs)
.set_intrinsicModuleDirectories(intrinsicIncludeDirs)
- .set_implicitUseModules(implicitUseModules)
.set_warnOnNonstandardUsage(warnStdViolation)
.set_warningsAreErrors(warnIsError);
More information about the flang-commits
mailing list