[flang-commits] [flang] f7be1aa - [flang] Prohibit multiple separate module procedure definitions

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Fri Jan 27 14:43:08 PST 2023


Author: Peter Klausler
Date: 2023-01-27T14:34:03-08:00
New Revision: f7be1aadf2d040b943b96a9ed52bf654faf33f08

URL: https://github.com/llvm/llvm-project/commit/f7be1aadf2d040b943b96a9ed52bf654faf33f08
DIFF: https://github.com/llvm/llvm-project/commit/f7be1aadf2d040b943b96a9ed52bf654faf33f08.diff

LOG: [flang] Prohibit multiple separate module procedure definitions

Ensure that non-BIND(C) separate module procedures are not
defined more than once.

Differential Revision: https://reviews.llvm.org/D142750

Added: 
    flang/test/Semantics/separate-mp04.f90

Modified: 
    flang/lib/Semantics/check-declarations.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/lib/Semantics/scope.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 6746d47a9b02..8b072999f82d 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -141,6 +141,7 @@ class CheckHelper {
   };
   void CheckAlreadySeenDefinedIo(const DerivedTypeSpec &,
       GenericKind::DefinedIo, const Symbol &, const Symbol &generic);
+  void CheckModuleProcedureDef(const Symbol &);
 
   SemanticsContext &context_;
   evaluate::FoldingContext &foldingContext_{context_.foldingContext()};
@@ -155,6 +156,9 @@ class CheckHelper {
       characterizeCache_;
   // Collection of symbols with BIND(C) names
   std::map<std::string, SymbolRef> bindC_;
+  // Collection of module procedure symbols with non-BIND(C)
+  // global names, qualified by their module.
+  std::map<std::pair<SourceName, const Symbol *>, SymbolRef> moduleProcs_;
   // Derived types that have defined input/output procedures
   std::vector<TypeWithDefinedIo> seenDefinedIoTypes_;
 };
@@ -1052,6 +1056,7 @@ void CheckHelper::CheckSubprogram(
     }
   }
   CheckLocalVsGlobal(symbol);
+  CheckModuleProcedureDef(symbol);
 }
 
 void CheckHelper::CheckLocalVsGlobal(const Symbol &symbol) {
@@ -1329,6 +1334,13 @@ void CheckHelper::CheckGeneric(
                     [](const auto &) {},
                 },
       details.kind().u);
+  // Ensure that shadowed symbols are checked
+  if (details.specific()) {
+    Check(*details.specific());
+  }
+  if (details.derivedType()) {
+    Check(*details.derivedType());
+  }
 }
 
 // Check that the specifics of this generic are distinguishable from each other
@@ -2442,6 +2454,40 @@ void CheckHelper::CheckSymbolType(const Symbol &symbol) {
   }
 }
 
+void CheckHelper::CheckModuleProcedureDef(const Symbol &symbol) {
+  auto procClass{ClassifyProcedure(symbol)};
+  if (const auto *subprogram{symbol.detailsIf<SubprogramDetails>()};
+      subprogram &&
+      (procClass == ProcedureDefinitionClass::Module &&
+          symbol.attrs().test(Attr::MODULE)) &&
+      !subprogram->bindName() && !subprogram->isInterface()) {
+    const Symbol *module{nullptr};
+    if (const Scope * moduleScope{FindModuleContaining(symbol.owner())};
+        moduleScope && moduleScope->symbol()) {
+      if (const auto *details{
+              moduleScope->symbol()->detailsIf<ModuleDetails>()}) {
+        if (details->parent()) {
+          moduleScope = details->parent();
+        }
+        module = moduleScope->symbol();
+      }
+    }
+    if (module) {
+      std::pair<SourceName, const Symbol *> key{symbol.name(), module};
+      auto iter{moduleProcs_.find(key)};
+      if (iter == moduleProcs_.end()) {
+        moduleProcs_.emplace(std::move(key), symbol);
+      } else if (
+          auto *msg{messages_.Say(symbol.name(),
+              "Module procedure '%s' in module '%s' has multiple definitions"_err_en_US,
+              symbol.name(), module->name())}) {
+        msg->Attach(iter->second->name(), "Previous definition of '%s'"_en_US,
+            symbol.name());
+      }
+    }
+  }
+}
+
 void SubprogramMatchHelper::Check(
     const Symbol &symbol1, const Symbol &symbol2) {
   const auto details1{symbol1.get<SubprogramDetails>()};

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index fdc3b3e350cc..d66b7592336c 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -3709,13 +3709,21 @@ Symbol *ScopeHandler::FindSeparateModuleProcedureInterface(
     const parser::Name &name) {
   auto *symbol{FindSymbol(name)};
   if (symbol && symbol->has<SubprogramNameDetails>()) {
-    symbol = FindSymbol(currScope().parent(), name);
+    const Scope *parent{nullptr};
+    if (currScope().IsSubmodule()) {
+      parent = currScope().symbol()->get<ModuleDetails>().parent();
+    }
+    symbol = parent ? FindSymbol(*parent, name) : nullptr;
   }
   if (symbol) {
     if (auto *generic{symbol->detailsIf<GenericDetails>()}) {
       symbol = generic->specific();
     }
   }
+  if (const Symbol * defnIface{FindSeparateModuleSubprogramInterface(symbol)}) {
+    // Error recovery in case of multiple definitions
+    symbol = const_cast<Symbol *>(defnIface);
+  }
   if (!IsSeparateModuleProcedureInterface(symbol)) {
     Say(name, "'%s' was not declared a separate module procedure"_err_en_US);
     symbol = nullptr;

diff  --git a/flang/lib/Semantics/scope.cpp b/flang/lib/Semantics/scope.cpp
index 387f8e7d4f10..bcffbd331280 100644
--- a/flang/lib/Semantics/scope.cpp
+++ b/flang/lib/Semantics/scope.cpp
@@ -88,6 +88,9 @@ Symbol *Scope::FindSymbol(const SourceName &name) const {
   auto it{find(name)};
   if (it != end()) {
     return &*it->second;
+  } else if (IsSubmodule()) {
+    const Scope *parent{symbol_->get<ModuleDetails>().parent()};
+    return parent ? parent->FindSymbol(name) : nullptr;
   } else if (CanImport(name)) {
     return parent_.FindSymbol(name);
   } else {

diff  --git a/flang/test/Semantics/separate-mp04.f90 b/flang/test/Semantics/separate-mp04.f90
new file mode 100644
index 000000000000..32005edd91a3
--- /dev/null
+++ b/flang/test/Semantics/separate-mp04.f90
@@ -0,0 +1,57 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Checks for multiple module procedure definitions
+
+module m1
+  interface
+    module subroutine x001
+    end subroutine
+    module subroutine x002
+    end subroutine
+    module subroutine x003
+    end subroutine
+  end interface
+end
+
+submodule(m1) sm1
+  interface
+    module subroutine x004
+    end subroutine
+  end interface
+ contains
+  module procedure x001 ! fine
+  end procedure
+  module subroutine x002
+  end subroutine
+  module subroutine x003
+  end subroutine
+end
+
+submodule(m1) sm2
+ contains
+  !ERROR: Module procedure 'x002' in module 'm1' has multiple definitions
+  module subroutine x002
+  end subroutine
+end
+
+submodule(m1:sm2) sm3
+ contains
+  !ERROR: Module procedure 'x002' in module 'm1' has multiple definitions
+  module subroutine x002
+  end subroutine
+  !ERROR: Module procedure 'x003' in module 'm1' has multiple definitions
+  module subroutine x003
+  end subroutine
+end
+
+submodule(m1:sm1) sm4
+ contains
+  module subroutine x004
+  end subroutine
+end
+
+submodule(m1:sm1) sm5
+ contains
+  !ERROR: Module procedure 'x004' in module 'm1' has multiple definitions
+  module subroutine x004
+  end subroutine
+end


        


More information about the flang-commits mailing list