forked from OSchip/llvm-project
[flang] Resolve names in ProcedureStmt and GenericStmt
We need to save the names of specific procedures that appear in a ProcedureStmt or GenericStmt to resolve at the end of the specification section. They may be forward references to interface bodies. We were saving them in the GenericDetails but that was not the right place: we need to save the parser::Name so that we can eventually resolve it to a Symbol, but the symbol table should not contains references to Name because they go away with the parse tree. The fix is to save the mapping in a new multimap, specificProcs_ in InterfaceVisitor. We can reference parser::Names there and resolve them during ResolveSpecificsInGenerics(). We no longer need to clutter GenericDetails with data structures for unresolved names. Also handle the case where a specific procedure is use-associated from another module. Original-commit: flang-compiler/f18@c7f7b1e72d Reviewed-on: https://github.com/flang-compiler/f18/pull/249 Tree-same-pre-rewrite: false
This commit is contained in:
parent
a040d7462e
commit
bc469ef570
|
@ -30,6 +30,7 @@
|
|||
#include "../parser/parse-tree-visitor.h"
|
||||
#include "../parser/parse-tree.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
|
@ -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<Symbol *, std::pair<const parser::Name *, ProcedureKind>>
|
||||
specificProcs_;
|
||||
|
||||
void AddSpecificProcs(const std::list<parser::Name> &, 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<parser::ProcedureStmt::Kind>(x.t) ==
|
||||
parser::ProcedureStmt::Kind::ModuleProcedure;
|
||||
for (const auto &name : std::get<std::list<parser::Name>>(x.t)) {
|
||||
GetGenericDetails().add_specificProcName(name.source, expectModuleProc);
|
||||
}
|
||||
auto kind{std::get<parser::ProcedureStmt::Kind>(x.t)};
|
||||
const auto &names{std::get<std::list<parser::Name>>(x.t)};
|
||||
AddSpecificProcs(names, kind);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1795,9 +1799,8 @@ void InterfaceVisitor::Post(const parser::GenericStmt &x) {
|
|||
if (auto &accessSpec{std::get<std::optional<parser::AccessSpec>>(x.t)}) {
|
||||
genericName_->symbol->attrs().set(AccessSpecToAttr(*accessSpec));
|
||||
}
|
||||
for (const auto &name : std::get<std::list<parser::Name>>(x.t)) {
|
||||
GetGenericDetails().add_specificProcName(name.source, false);
|
||||
}
|
||||
const auto &names{std::get<std::list<parser::Name>>(x.t)};
|
||||
AddSpecificProcs(names, ProcedureKind::Procedure);
|
||||
}
|
||||
|
||||
GenericDetails &InterfaceVisitor::GetGenericDetails() {
|
||||
|
@ -1806,6 +1809,13 @@ GenericDetails &InterfaceVisitor::GetGenericDetails() {
|
|||
return genericName_->symbol->get<GenericDetails>();
|
||||
}
|
||||
|
||||
void InterfaceVisitor::AddSpecificProcs(
|
||||
const std::list<parser::Name> &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<GenericDetails>().specific()}) {
|
||||
symbol = specific;
|
||||
|
@ -1827,23 +1841,24 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
|
|||
}
|
||||
if (!symbol->has<SubprogramDetails>() &&
|
||||
!symbol->has<SubprogramNameDetails>()) {
|
||||
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<SubprogramNameDetails>()};
|
||||
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.
|
||||
|
|
|
@ -257,20 +257,14 @@ private:
|
|||
class GenericDetails {
|
||||
public:
|
||||
using listType = std::list<const Symbol *>;
|
||||
using procNamesType = std::list<std::pair<SourceName, bool>>;
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue