diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 6746d47a9b02f..8b072999f82db 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 bindC_; + // Collection of module procedure symbols with non-BIND(C) + // global names, qualified by their module. + std::map, SymbolRef> moduleProcs_; // Derived types that have defined input/output procedures std::vector 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()}; + 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()}) { + if (details->parent()) { + moduleScope = details->parent(); + } + module = moduleScope->symbol(); + } + } + if (module) { + std::pair 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()}; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index fdc3b3e350cc2..d66b7592336c0 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()) { - symbol = FindSymbol(currScope().parent(), name); + const Scope *parent{nullptr}; + if (currScope().IsSubmodule()) { + parent = currScope().symbol()->get().parent(); + } + symbol = parent ? FindSymbol(*parent, name) : nullptr; } if (symbol) { if (auto *generic{symbol->detailsIf()}) { symbol = generic->specific(); } } + if (const Symbol * defnIface{FindSeparateModuleSubprogramInterface(symbol)}) { + // Error recovery in case of multiple definitions + symbol = const_cast(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 387f8e7d4f105..bcffbd331280c 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().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 0000000000000..32005edd91a31 --- /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