[flang-commits] [flang] [flang] Add ability to implicitly use a module (PR #207824)

Valentin Clement バレンタイン クレメン via flang-commits flang-commits at lists.llvm.org
Mon Jul 6 17:00:48 PDT 2026


https://github.com/clementval updated https://github.com/llvm/llvm-project/pull/207824

>From 2d7740b4648f13d20f3967d709bd0bffc07d677b Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 6 Jul 2026 12:55:01 -0700
Subject: [PATCH 1/3] [flang] Add ability to implicitly use a module

---
 flang/include/flang/Parser/options.h          |  1 +
 flang/include/flang/Semantics/semantics.h     |  8 ++
 flang/lib/Semantics/resolve-names.cpp         | 87 ++++++++++++++-----
 flang/test/Driver/bbc-implicit-use-module.f90 | 20 +++++
 flang/tools/bbc/bbc.cpp                       |  8 ++
 5 files changed, 102 insertions(+), 22 deletions(-)
 create mode 100644 flang/test/Driver/bbc-implicit-use-module.f90

diff --git a/flang/include/flang/Parser/options.h b/flang/include/flang/Parser/options.h
index e65f253748d26..8a9fcd0568652 100644
--- a/flang/include/flang/Parser/options.h
+++ b/flang/include/flang/Parser/options.h
@@ -28,6 +28,7 @@ struct Options {
   common::LanguageFeatureControl features;
   std::vector<std::string> searchDirectories;
   std::vector<std::string> intrinsicModuleDirectories;
+  std::vector<std::string> implicitUseModules;
   std::vector<Predefinition> predefinitions;
   bool instrumentedParse{false};
   bool isModuleFile{false};
diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h
index 575851920aa9f..b5bccac599973 100644
--- a/flang/include/flang/Semantics/semantics.h
+++ b/flang/include/flang/Semantics/semantics.h
@@ -101,6 +101,9 @@ class SemanticsContext {
   const std::vector<std::string> &intrinsicModuleDirectories() const {
     return intrinsicModuleDirectories_;
   }
+  const std::vector<std::string> &implicitUseModules() const {
+    return implicitUseModules_;
+  }
   const std::string &moduleDirectory() const { return moduleDirectory_; }
   const std::string &moduleFileSuffix() const { return moduleFileSuffix_; }
   bool underscoring() const { return underscoring_; }
@@ -145,6 +148,10 @@ class SemanticsContext {
     intrinsicModuleDirectories_ = x;
     return *this;
   }
+  SemanticsContext &set_implicitUseModules(const std::vector<std::string> &x) {
+    implicitUseModules_ = x;
+    return *this;
+  }
   SemanticsContext &set_moduleDirectory(const std::string &x) {
     moduleDirectory_ = x;
     return *this;
@@ -391,6 +398,7 @@ class SemanticsContext {
   std::optional<parser::CharBlock> location_;
   std::vector<std::string> searchDirectories_;
   std::vector<std::string> intrinsicModuleDirectories_;
+  std::vector<std::string> implicitUseModules_;
   std::string moduleDirectory_{"."s};
   std::string moduleFileSuffix_{".mod"};
   std::string targetTriple_;
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 9ddda9a92471b..6079cfced9151 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -825,6 +825,7 @@ class ModuleVisitor : public virtual ScopeHandler {
   Symbol &AddGenericUse(GenericDetails &, const SourceName &, const Symbol &);
   void AddAndCheckModuleUse(SourceName, bool isIntrinsic);
   void CollectUseRenames(const parser::UseStmt &);
+  void AddImplicitUseModules();
   void ClearUseRenames() { useRenames_.clear(); }
   void ClearUseOnly() { useOnly_.clear(); }
   void ClearModuleUses() {
@@ -855,6 +856,8 @@ class ModuleVisitor : public virtual ScopeHandler {
   // Record a use from useModuleScope_ of use Name/Symbol as local Name/Symbol
   SymbolRename AddUse(const SourceName &localName, const SourceName &useName);
   SymbolRename AddUse(const SourceName &, const SourceName &, Symbol *);
+  void AddUseForPublicSymbols(SourceName, const std::set<SourceName> &);
+  void AddUseForCommonBlocks();
   void DoAddUse(
       SourceName, SourceName, Symbol &localSymbol, const Symbol &useSymbol);
   void AddUse(const GenericSpecInfo &);
@@ -3862,30 +3865,40 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
                     },
           rename.u);
     }
-    for (const auto &[name, symbol] : *useModuleScope_) {
-      // Default USE imports public names, excluding intrinsic-only and most
-      // miscellaneous details. Allow OpenMP mapper identifiers represented
-      // as MapperDetails, and also legacy MiscDetails::ConstructName.
-      bool isMapper{symbol->has<MapperDetails>()};
-      if (!isMapper) {
-        if (const auto *misc{symbol->detailsIf<MiscDetails>()}) {
-          isMapper = misc->kind() == MiscDetails::Kind::ConstructName;
-        }
-      }
-      if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) &&
-          (!symbol->implicitAttrs().test(Attr::INTRINSIC) ||
-              symbol->has<UseDetails>()) &&
-          (!symbol->has<MiscDetails>() || isMapper) &&
-          useNames.count(name) == 0) {
-        SourceName location{x.moduleName.source};
-        if (auto *localSymbol{FindInScope(name)}) {
-          DoAddUse(location, localSymbol->name(), *localSymbol, *symbol);
-        } else {
-          DoAddUse(location, location, CopySymbol(name, *symbol), *symbol);
-        }
+    AddUseForPublicSymbols(x.moduleName.source, useNames);
+  }
+  AddUseForCommonBlocks();
+
+  useModuleScope_ = nullptr;
+}
+
+void ModuleVisitor::AddUseForPublicSymbols(
+    SourceName location, const std::set<SourceName> &useNames) {
+  for (const auto &[name, symbol] : *useModuleScope_) {
+    // Default USE imports public names, excluding intrinsic-only and most
+    // miscellaneous details. Allow OpenMP mapper identifiers represented
+    // as MapperDetails, and also legacy MiscDetails::ConstructName.
+    bool isMapper{symbol->has<MapperDetails>()};
+    if (!isMapper) {
+      if (const auto *misc{symbol->detailsIf<MiscDetails>()}) {
+        isMapper = misc->kind() == MiscDetails::Kind::ConstructName;
+      }
+    }
+    if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) &&
+        (!symbol->implicitAttrs().test(Attr::INTRINSIC) ||
+            symbol->has<UseDetails>()) &&
+        (!symbol->has<MiscDetails>() || isMapper) &&
+        useNames.count(name) == 0) {
+      if (auto *localSymbol{FindInScope(name)}) {
+        DoAddUse(location, localSymbol->name(), *localSymbol, *symbol);
+      } else {
+        DoAddUse(location, location, CopySymbol(name, *symbol), *symbol);
       }
     }
   }
+}
+
+void ModuleVisitor::AddUseForCommonBlocks() {
   // Go through the list of COMMON block symbols in the module scope and add
   // their USE association to the current scope's USE-associated COMMON blocks.
   for (const auto &[name, symbol] : useModuleScope_->commonBlocks()) {
@@ -3900,8 +3913,37 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
   for (const auto &[name, symbol] : useModuleScope_->commonBlockUses()) {
     currScope().AddCommonBlockUse(name, symbol->attrs(), symbol->GetUltimate());
   }
+}
 
-  useModuleScope_ = nullptr;
+void ModuleVisitor::AddImplicitUseModules() {
+  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) {
+      continue;
+    }
+    parser::Name name{moduleName};
+    std::optional<bool> isIntrinsic;
+    if (currScope().IsModule() && currScope().symbol() &&
+        currScope().symbol()->attrs().test(Attr::INTRINSIC)) {
+      // Intrinsic modules USE only other intrinsic modules.
+      isIntrinsic = true;
+    }
+    useModuleScope_ = FindModule(name, isIntrinsic);
+    if (!useModuleScope_) {
+      continue;
+    }
+    AddAndCheckModuleUse(moduleName,
+        useModuleScope_->parent().kind() == Scope::Kind::IntrinsicModules);
+    useModuleScope_->symbol()->ReplaceName(moduleName);
+    AddUseForPublicSymbols(moduleName, {});
+    AddUseForCommonBlocks();
+    useModuleScope_ = nullptr;
+  }
 }
 
 ModuleVisitor::SymbolRename ModuleVisitor::AddUse(
@@ -10297,6 +10339,7 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
     CollectUseRenames(useStmt.statement.value());
   }
   Walk(useStmts);
+  AddImplicitUseModules();
   UseCUDABuiltinNames();
   ClearUseRenames();
   ClearUseOnly();
diff --git a/flang/test/Driver/bbc-implicit-use-module.f90 b/flang/test/Driver/bbc-implicit-use-module.f90
new file mode 100644
index 0000000000000..c9eb6ce444df8
--- /dev/null
+++ b/flang/test/Driver/bbc-implicit-use-module.f90
@@ -0,0 +1,20 @@
+! Test bbc's test-only implicit USE module hook.
+
+! RUN: split-file %s %t
+! RUN: bbc -module %t %t/implicit_mod.f90 -o /dev/null
+! RUN: bbc -emit-hlfir -I %t -implicit-use-module implicit_mod %t/use_implicit.f90 -o - | FileCheck %s
+
+!--- implicit_mod.f90
+module implicit_mod
+  implicit none
+  integer :: module_value = 42
+end module
+
+!--- use_implicit.f90
+subroutine use_implicit
+  integer :: x
+  x = module_value
+end subroutine
+
+! CHECK-LABEL: func.func @_QPuse_implicit()
+! CHECK: fir.address_of(@_QMimplicit_modEmodule_value) : !fir.ref<i32>
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 23e7af238198f..1f3a280438134 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -95,6 +95,10 @@ static llvm::cl::alias includeAlias("module-directory",
 static llvm::cl::list<std::string>
     intrinsicIncludeDirs("J", llvm::cl::desc("intrinsic module search paths"));
 
+static llvm::cl::list<std::string> implicitUseModules(
+    "implicit-use-module",
+    llvm::cl::desc("implicitly USE the named module for testing"));
+
 static llvm::cl::alias
     intrinsicIncludeAlias("intrinsic-module-directory",
                           llvm::cl::desc("intrinsic module directory"),
@@ -621,6 +625,9 @@ int main(int argc, char **argv) {
   }
 
   Fortran::parser::Options options;
+  options.implicitUseModules.insert(options.implicitUseModules.end(),
+                                    implicitUseModules.begin(),
+                                    implicitUseModules.end());
   options.predefinitions.emplace_back("__flang__"s, "1"s);
   options.predefinitions.emplace_back("__flang_major__"s,
                                       std::string{FLANG_VERSION_MAJOR_STRING});
@@ -691,6 +698,7 @@ int main(int argc, char **argv) {
       .set_moduleFileSuffix(moduleSuffix)
       .set_searchDirectories(includeDirs)
       .set_intrinsicModuleDirectories(intrinsicIncludeDirs)
+      .set_implicitUseModules(options.implicitUseModules)
       .set_warnOnNonstandardUsage(warnStdViolation)
       .set_warningsAreErrors(warnIsError);
 

>From c89213d50a12d865ffd8c971ef1ebef9edee8058 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 6 Jul 2026 13:45:03 -0700
Subject: [PATCH 2/3] Add common block

---
 flang/test/Driver/bbc-implicit-use-module.f90 | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/flang/test/Driver/bbc-implicit-use-module.f90 b/flang/test/Driver/bbc-implicit-use-module.f90
index c9eb6ce444df8..733ad69580c1c 100644
--- a/flang/test/Driver/bbc-implicit-use-module.f90
+++ b/flang/test/Driver/bbc-implicit-use-module.f90
@@ -2,19 +2,25 @@
 
 ! RUN: split-file %s %t
 ! RUN: bbc -module %t %t/implicit_mod.f90 -o /dev/null
-! RUN: bbc -emit-hlfir -I %t -implicit-use-module implicit_mod %t/use_implicit.f90 -o - | FileCheck %s
+! RUN: bbc -emit-hlfir -fopenacc -I %t -implicit-use-module implicit_mod %t/use_implicit.f90 -o - | FileCheck %s
 
 !--- implicit_mod.f90
 module implicit_mod
   implicit none
+  integer :: common_value
   integer :: module_value = 42
+  common /implicit_common/ common_value
 end module
 
 !--- use_implicit.f90
 subroutine use_implicit
   integer :: x
-  x = module_value
+  !$acc data copy(/implicit_common/)
+  x = module_value + common_value
+  !$acc end data
 end subroutine
 
 ! CHECK-LABEL: func.func @_QPuse_implicit()
-! CHECK: fir.address_of(@_QMimplicit_modEmodule_value) : !fir.ref<i32>
+! 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]]

>From 71fbbccb64c6b19aaabc0dfabb0ceb4a37011560 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 6 Jul 2026 14:02:41 -0700
Subject: [PATCH 3/3] Simplify

---
 flang/include/flang/Parser/options.h | 1 -
 flang/tools/bbc/bbc.cpp              | 5 +----
 2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/flang/include/flang/Parser/options.h b/flang/include/flang/Parser/options.h
index 8a9fcd0568652..e65f253748d26 100644
--- a/flang/include/flang/Parser/options.h
+++ b/flang/include/flang/Parser/options.h
@@ -28,7 +28,6 @@ struct Options {
   common::LanguageFeatureControl features;
   std::vector<std::string> searchDirectories;
   std::vector<std::string> intrinsicModuleDirectories;
-  std::vector<std::string> implicitUseModules;
   std::vector<Predefinition> predefinitions;
   bool instrumentedParse{false};
   bool isModuleFile{false};
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 1f3a280438134..88fa43c748e2f 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -625,9 +625,6 @@ int main(int argc, char **argv) {
   }
 
   Fortran::parser::Options options;
-  options.implicitUseModules.insert(options.implicitUseModules.end(),
-                                    implicitUseModules.begin(),
-                                    implicitUseModules.end());
   options.predefinitions.emplace_back("__flang__"s, "1"s);
   options.predefinitions.emplace_back("__flang_major__"s,
                                       std::string{FLANG_VERSION_MAJOR_STRING});
@@ -698,7 +695,7 @@ int main(int argc, char **argv) {
       .set_moduleFileSuffix(moduleSuffix)
       .set_searchDirectories(includeDirs)
       .set_intrinsicModuleDirectories(intrinsicIncludeDirs)
-      .set_implicitUseModules(options.implicitUseModules)
+      .set_implicitUseModules(implicitUseModules)
       .set_warnOnNonstandardUsage(warnStdViolation)
       .set_warningsAreErrors(warnIsError);
 



More information about the flang-commits mailing list