diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index 35011bf9a6ab..40dd76bacf11 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -30,6 +30,7 @@ #include "../parser/parse-tree-visitor.h" #include "../parser/parse-tree.h" #include +#include #include #include #include @@ -504,7 +505,12 @@ private: bool inInterfaceBlock_{false}; // set when in interface block bool isAbstract_{false}; // set when in abstract interface block const parser::Name *genericName_{nullptr}; // set in generic interface block + using ProcedureKind = parser::ProcedureStmt::Kind; + // mapping of generic to its specific proc names and kinds + std::multimap> + specificProcs_; + void AddSpecificProcs(const std::list &, ProcedureKind); void ResolveSpecificsInGeneric(Symbol &generic); }; @@ -1783,11 +1789,9 @@ bool InterfaceVisitor::Pre(const parser::ProcedureStmt &x) { Say("A PROCEDURE statement is only allowed in a generic interface block"_err_en_US); return false; } - bool expectModuleProc = std::get(x.t) == - parser::ProcedureStmt::Kind::ModuleProcedure; - for (const auto &name : std::get>(x.t)) { - GetGenericDetails().add_specificProcName(name.source, expectModuleProc); - } + auto kind{std::get(x.t)}; + const auto &names{std::get>(x.t)}; + AddSpecificProcs(names, kind); return false; } @@ -1795,9 +1799,8 @@ void InterfaceVisitor::Post(const parser::GenericStmt &x) { if (auto &accessSpec{std::get>(x.t)}) { genericName_->symbol->attrs().set(AccessSpecToAttr(*accessSpec)); } - for (const auto &name : std::get>(x.t)) { - GetGenericDetails().add_specificProcName(name.source, false); - } + const auto &names{std::get>(x.t)}; + AddSpecificProcs(names, ProcedureKind::Procedure); } GenericDetails &InterfaceVisitor::GetGenericDetails() { @@ -1806,6 +1809,13 @@ GenericDetails &InterfaceVisitor::GetGenericDetails() { return genericName_->symbol->get(); } +void InterfaceVisitor::AddSpecificProcs( + const std::list &names, ProcedureKind kind) { + for (const auto &name : names) { + specificProcs_.emplace(genericName_->symbol, std::make_pair(&name, kind)); + } +} + // By now we should have seen all specific procedures referenced by name in // this generic interface. Resolve those names to symbols. void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) { @@ -1814,12 +1824,16 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) { for (const auto *symbol : details.specificProcs()) { namesSeen.insert(symbol->name()); } - for (const auto &[name, expectModuleProc] : details.specificProcNames()) { - const auto *symbol{currScope().FindSymbol(name)}; + auto range{specificProcs_.equal_range(&generic)}; + for (auto it{range.first}; it != range.second; ++it) { + auto *name{it->second.first}; + auto kind{it->second.second}; + const auto *symbol{FindSymbol(*name)}; if (!symbol) { - Say(name, "Procedure '%s' not found"_err_en_US); + Say(*name, "Procedure '%s' not found"_err_en_US); continue; } + symbol = &symbol->GetUltimate(); if (symbol == &generic) { if (auto *specific{generic.get().specific()}) { symbol = specific; @@ -1827,23 +1841,24 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) { } if (!symbol->has() && !symbol->has()) { - Say(name, "'%s' is not a subprogram"_err_en_US); + Say(*name, "'%s' is not a subprogram"_err_en_US); continue; } - if (expectModuleProc) { + if (kind == ProcedureKind::ModuleProcedure) { const auto *d{symbol->detailsIf()}; if (!d || d->kind() != SubprogramKind::Module) { - Say(name, "'%s' is not a module procedure"_err_en_US); + Say(*name, "'%s' is not a module procedure"_err_en_US); } } - if (!namesSeen.insert(name).second) { - Say(name, "Procedure '%s' is already specified in generic '%s'"_err_en_US, - name, generic.name()); + if (!namesSeen.insert(name->source).second) { + Say(*name, + "Procedure '%s' is already specified in generic '%s'"_err_en_US, + name->source, generic.name()); continue; } details.add_specificProc(symbol); } - details.ClearSpecificProcNames(); + specificProcs_.erase(range.first, range.second); } // Check that the specific procedures are all functions or all subroutines. diff --git a/flang/lib/semantics/symbol.h b/flang/lib/semantics/symbol.h index 2fc788cd43d7..bdd6aea568bd 100644 --- a/flang/lib/semantics/symbol.h +++ b/flang/lib/semantics/symbol.h @@ -257,20 +257,14 @@ private: class GenericDetails { public: using listType = std::list; - using procNamesType = std::list>; GenericDetails() {} GenericDetails(const listType &specificProcs); GenericDetails(Symbol *specific) : specific_{specific} {} const listType specificProcs() const { return specificProcs_; } - const procNamesType specificProcNames() const { return specificProcNames_; } void add_specificProc(const Symbol *proc) { specificProcs_.push_back(proc); } - void add_specificProcName(const SourceName &name, bool isModuleProc) { - specificProcNames_.emplace_back(name, isModuleProc); - } - void ClearSpecificProcNames() { specificProcNames_.clear(); } Symbol *specific() { return specific_; } void set_specific(Symbol &specific); @@ -287,8 +281,6 @@ public: private: // all of the specific procedures for this generic listType specificProcs_; - // specific procs referenced by name and whether it's a module proc - procNamesType specificProcNames_; // a specific procedure with the same name as this generic, if any Symbol *specific_{nullptr}; // a derived type with the same name as this generic, if any diff --git a/flang/test/semantics/CMakeLists.txt b/flang/test/semantics/CMakeLists.txt index 1bece69aa780..76b3ac49f7bb 100644 --- a/flang/test/semantics/CMakeLists.txt +++ b/flang/test/semantics/CMakeLists.txt @@ -75,6 +75,7 @@ set(SYMBOL_TESTS symbol07.f90 symbol08.f90 symbol09.f90 + symbol10.f90 ) # These test files have expected .mod file contents in the source diff --git a/flang/test/semantics/symbol10.f90 b/flang/test/semantics/symbol10.f90 new file mode 100644 index 000000000000..009f4049e9d7 --- /dev/null +++ b/flang/test/semantics/symbol10.f90 @@ -0,0 +1,53 @@ +! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +! +! Licensed under the Apache License, Version 2.0 (the "License"); +! you may not use this file except in compliance with the License. +! You may obtain a copy of the License at +! +! http://www.apache.org/licenses/LICENSE-2.0 +! +! Unless required by applicable law or agreed to in writing, software +! distributed under the License is distributed on an "AS IS" BASIS, +! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +! See the License for the specific language governing permissions and +! limitations under the License. + +!DEF: /m1 Module +module m1 +contains + !DEF: /m1/foo_complex PUBLIC Subprogram + !DEF: /m1/foo_complex/z ObjectEntity COMPLEX(4) + subroutine foo_complex (z) + !REF: /m1/foo_complex/z + complex z + end subroutine +end module +!DEF: /m2 Module +module m2 + !REF: /m1 + use :: m1 + !DEF: /m2/foo PUBLIC Generic + interface foo + !DEF: /m2/foo_int PUBLIC Subprogram + module procedure :: foo_int + !DEF: /m2/foo_real EXTERNAL, PUBLIC Subprogram + procedure :: foo_real + !DEF: /m2/foo_complex PUBLIC Use + procedure :: foo_complex + end interface + interface + !REF: /m2/foo_real + !DEF: /m2/foo_real/r ObjectEntity REAL(4) + subroutine foo_real (r) + !REF: /m2/foo_real/r + real r + end subroutine + end interface +contains + !REF: /m2/foo_int + !DEF: /m2/foo_int/i ObjectEntity INTEGER(4) + subroutine foo_int (i) + !REF: /m2/foo_int/i + integer i + end subroutine +end module