forked from OSchip/llvm-project
[flang] Process specification parts before execution parts
Change the order in which names are resolved. Before resolving names in the execution part of a subprogram we need to know the interface of contained subprograms. This is because the type of some construct entities can depend on the return type of contained functions, e.g. ``` associate(x => f()) end associate contains function f()... ``` To do this, we now build a tree rooted at each program unit with child nodes corresponding to subprograms contained in the parent. This provides flexibility in choosing an order to resolve names. The current implementation processes all specification parts before any execution parts. This ensures contained subprogram interfaces are know before analyzing constructs like ASSOCIATE. Resolving a specification part involves first adding `SubprogramNameDetails` symbols for each contained subprogram, then processing the statement that introduces the program unit (`ModuleStmt`, `SubroutineStmt`, etc.), then visiting all of the statements in the specification part. If it proves necessary, we can add a phase to do implicit declarations in the execution part before processing the specification part of contained subprograms. Original-commit: flang-compiler/f18@20e803fd92 Reviewed-on: https://github.com/flang-compiler/f18/pull/443 Tree-same-pre-rewrite: false
This commit is contained in:
parent
12f1660117
commit
14094c71c8
|
@ -286,4 +286,158 @@ Bound ArraySpecAnalyzer::GetBound(const parser::SpecificationExpr &x) {
|
|||
return Bound{std::move(expr)};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
|
||||
const auto &spec{std::get<parser::SpecificationPart>(x.t)};
|
||||
const auto &exec{std::get<parser::ExecutionPart>(x.t)};
|
||||
const auto &subps{
|
||||
std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
|
||||
ProgramTree node{name, spec, &exec};
|
||||
if (subps) {
|
||||
for (const auto &subp :
|
||||
std::get<std::list<parser::InternalSubprogram>>(subps->t)) {
|
||||
std::visit(
|
||||
[&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
|
||||
subp.u);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static ProgramTree BuildModuleTree(const parser::Name &name, const T &x) {
|
||||
const auto &spec{std::get<parser::SpecificationPart>(x.t)};
|
||||
const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
|
||||
ProgramTree node{name, spec};
|
||||
if (subps) {
|
||||
for (const auto &subp :
|
||||
std::get<std::list<parser::ModuleSubprogram>>(subps->t)) {
|
||||
std::visit(
|
||||
[&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
|
||||
subp.u);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
ProgramTree ProgramTree::Build(const parser::ProgramUnit &x) {
|
||||
return std::visit([](const auto &y) { return Build(y.value()); }, x.u);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::MainProgram &x) {
|
||||
const auto &stmt{
|
||||
std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(x.t)};
|
||||
const auto &end{std::get<parser::Statement<parser::EndProgramStmt>>(x.t)};
|
||||
static parser::Name emptyName;
|
||||
const auto &name{stmt ? stmt->statement.v : emptyName};
|
||||
return BuildSubprogramTree(name, x).set_stmt(*stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::FunctionSubprogram &x) {
|
||||
const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
|
||||
const auto &end{std::get<parser::Statement<parser::EndFunctionStmt>>(x.t)};
|
||||
const auto &name{std::get<parser::Name>(stmt.statement.t)};
|
||||
return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::SubroutineSubprogram &x) {
|
||||
const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)};
|
||||
const auto &end{std::get<parser::Statement<parser::EndSubroutineStmt>>(x.t)};
|
||||
const auto &name{std::get<parser::Name>(stmt.statement.t)};
|
||||
return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::SeparateModuleSubprogram &x) {
|
||||
const auto &stmt{std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t)};
|
||||
const auto &end{
|
||||
std::get<parser::Statement<parser::EndMpSubprogramStmt>>(x.t)};
|
||||
const auto &name{stmt.statement.v};
|
||||
return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::Module &x) {
|
||||
const auto &stmt{std::get<parser::Statement<parser::ModuleStmt>>(x.t)};
|
||||
const auto &end{std::get<parser::Statement<parser::EndModuleStmt>>(x.t)};
|
||||
const auto &name{stmt.statement.v};
|
||||
return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::Submodule &x) {
|
||||
const auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
|
||||
const auto &end{std::get<parser::Statement<parser::EndSubmoduleStmt>>(x.t)};
|
||||
const auto &name{std::get<parser::Name>(stmt.statement.t)};
|
||||
return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
|
||||
}
|
||||
ProgramTree ProgramTree::Build(const parser::BlockData &x) {
|
||||
DIE("BlockData not yet implemented");
|
||||
}
|
||||
|
||||
const parser::ParentIdentifier &ProgramTree::GetParentId() const {
|
||||
const auto *stmt{
|
||||
std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};
|
||||
return std::get<parser::ParentIdentifier>(stmt->statement.t);
|
||||
}
|
||||
|
||||
bool ProgramTree::IsModule() const {
|
||||
auto kind{GetKind()};
|
||||
return kind == Kind::Module || kind == Kind::Submodule;
|
||||
}
|
||||
|
||||
Symbol::Flag ProgramTree::GetSubpFlag() const {
|
||||
return GetKind() == Kind::Function ? Symbol::Flag::Function
|
||||
: Symbol::Flag::Subroutine;
|
||||
}
|
||||
|
||||
bool ProgramTree::HasModulePrefix() const {
|
||||
using ListType = std::list<parser::PrefixSpec>;
|
||||
const auto *prefixes{std::visit(
|
||||
common::visitors{
|
||||
[](const parser::Statement<parser::FunctionStmt> *x) {
|
||||
return &std::get<ListType>(x->statement.t);
|
||||
},
|
||||
[](const parser::Statement<parser::SubroutineStmt> *x) {
|
||||
return &std::get<ListType>(x->statement.t);
|
||||
},
|
||||
[](const auto *) -> const ListType * { return nullptr; },
|
||||
},
|
||||
stmt_)};
|
||||
if (prefixes) {
|
||||
for (const auto &prefix : *prefixes) {
|
||||
if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProgramTree::Kind ProgramTree::GetKind() const {
|
||||
return std::visit(
|
||||
common::visitors{
|
||||
[](const parser::Statement<parser::ProgramStmt> *) {
|
||||
return Kind::Program;
|
||||
},
|
||||
[](const parser::Statement<parser::FunctionStmt> *) {
|
||||
return Kind::Function;
|
||||
},
|
||||
[](const parser::Statement<parser::SubroutineStmt> *) {
|
||||
return Kind::Subroutine;
|
||||
},
|
||||
[](const parser::Statement<parser::MpSubprogramStmt> *) {
|
||||
return Kind::MpSubprogram;
|
||||
},
|
||||
[](const parser::Statement<parser::ModuleStmt> *) {
|
||||
return Kind::Module;
|
||||
},
|
||||
[](const parser::Statement<parser::SubmoduleStmt> *) {
|
||||
return Kind::Submodule;
|
||||
},
|
||||
},
|
||||
stmt_);
|
||||
}
|
||||
|
||||
void ProgramTree::set_scope(Scope &scope) {
|
||||
scope_ = &scope;
|
||||
CHECK(endStmt_);
|
||||
scope.AddSourceRange(*endStmt_);
|
||||
}
|
||||
|
||||
void ProgramTree::AddChild(ProgramTree &&child) {
|
||||
children_.emplace_back(std::move(child));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,16 +20,7 @@
|
|||
#include "symbol.h"
|
||||
#include "type.h"
|
||||
#include "../parser/message.h"
|
||||
|
||||
namespace Fortran::parser {
|
||||
class CharBlock;
|
||||
struct ArraySpec;
|
||||
struct ComponentArraySpec;
|
||||
struct CoarraySpec;
|
||||
struct DefinedOpName;
|
||||
struct GenericSpec;
|
||||
struct Name;
|
||||
}
|
||||
#include "../parser/parse-tree.h"
|
||||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
|
@ -76,6 +67,69 @@ ArraySpec AnalyzeArraySpec(
|
|||
ArraySpec AnalyzeCoarraySpec(
|
||||
SemanticsContext &context, const parser::CoarraySpec &);
|
||||
|
||||
}
|
||||
// A tree of program units and their contained subprograms.
|
||||
// The root nodes represent: main program, function, subroutine,
|
||||
// module subprogram, module, or submodule.
|
||||
class ProgramTree {
|
||||
public:
|
||||
static ProgramTree Build(const parser::ProgramUnit &);
|
||||
static ProgramTree Build(const parser::MainProgram &);
|
||||
static ProgramTree Build(const parser::FunctionSubprogram &);
|
||||
static ProgramTree Build(const parser::SubroutineSubprogram &);
|
||||
static ProgramTree Build(const parser::SeparateModuleSubprogram &);
|
||||
static ProgramTree Build(const parser::Module &);
|
||||
static ProgramTree Build(const parser::Submodule &);
|
||||
static ProgramTree Build(const parser::BlockData &);
|
||||
|
||||
ENUM_CLASS(Kind, // kind of node
|
||||
Program, Function, Subroutine, MpSubprogram, Module, Submodule)
|
||||
using Stmt = std::variant< // the statement that introduces the program unit
|
||||
const parser::Statement<parser::ProgramStmt> *,
|
||||
const parser::Statement<parser::FunctionStmt> *,
|
||||
const parser::Statement<parser::SubroutineStmt> *,
|
||||
const parser::Statement<parser::MpSubprogramStmt> *,
|
||||
const parser::Statement<parser::ModuleStmt> *,
|
||||
const parser::Statement<parser::SubmoduleStmt> *>;
|
||||
|
||||
ProgramTree(const parser::Name &name, const parser::SpecificationPart &spec,
|
||||
const parser::ExecutionPart *exec = nullptr)
|
||||
: name_{name}, spec_{spec}, exec_{exec} {}
|
||||
|
||||
const parser::Name &name() const { return name_; }
|
||||
Kind GetKind() const;
|
||||
const Stmt &stmt() const { return stmt_; }
|
||||
const parser::ParentIdentifier &GetParentId() const; // only for Submodule
|
||||
const parser::SpecificationPart &spec() const { return spec_; }
|
||||
const parser::ExecutionPart *exec() const { return exec_; }
|
||||
std::vector<ProgramTree> &children() { return children_; }
|
||||
const std::vector<ProgramTree> &children() const { return children_; }
|
||||
Symbol::Flag GetSubpFlag() const;
|
||||
bool IsModule() const; // Module or Submodule
|
||||
bool HasModulePrefix() const; // in function or subroutine stmt
|
||||
Scope *scope() const { return scope_; }
|
||||
void set_scope(Scope &);
|
||||
void AddChild(ProgramTree &&);
|
||||
|
||||
template<typename T> ProgramTree &set_stmt(const parser::Statement<T> &stmt) {
|
||||
stmt_ = &stmt;
|
||||
return *this;
|
||||
}
|
||||
template<typename T>
|
||||
ProgramTree &set_endStmt(const parser::Statement<T> &stmt) {
|
||||
endStmt_ = &stmt.source;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const parser::Name &name_;
|
||||
Stmt stmt_{
|
||||
static_cast<const parser::Statement<parser::ProgramStmt> *>(nullptr)};
|
||||
const parser::SpecificationPart &spec_;
|
||||
const parser::ExecutionPart *exec_{nullptr};
|
||||
std::vector<ProgramTree> children_;
|
||||
Scope *scope_{nullptr};
|
||||
const parser::CharBlock *endStmt_{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
|
||||
|
|
|
@ -397,10 +397,7 @@ public:
|
|||
void PushScope(Scope::Kind kind, Symbol *symbol);
|
||||
void PushScope(Scope &scope);
|
||||
void PopScope();
|
||||
void ClearScopes() {
|
||||
PopScope(); // trigger ConvertToObjectEntity calls
|
||||
currScope_ = &context().globalScope();
|
||||
}
|
||||
void SetScope(Scope &);
|
||||
|
||||
template<typename T> bool Pre(const parser::Statement<T> &x) {
|
||||
messageHandler().set_currStmtSource(&x.source);
|
||||
|
@ -499,10 +496,6 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
// When subpNamesOnly_ is set we are only collecting procedure names.
|
||||
// Create symbols with SubprogramNameDetails of the given kind.
|
||||
std::optional<SubprogramKind> subpNamesOnly_;
|
||||
|
||||
// Apply the implicit type rules to this symbol.
|
||||
void ApplyImplicitRules(Symbol &);
|
||||
const DeclTypeSpec *GetImplicitType(Symbol &);
|
||||
|
@ -514,32 +507,12 @@ protected:
|
|||
const DeclTypeSpec &MakeLogicalType(
|
||||
const std::optional<parser::KindSelector> &);
|
||||
|
||||
// Walk the ModuleSubprogramPart or InternalSubprogramPart collecting names.
|
||||
template<typename T>
|
||||
void WalkSubprogramPart(const std::optional<T> &subpPart) {
|
||||
if (subpPart) {
|
||||
if (std::is_same_v<T, parser::ModuleSubprogramPart>) {
|
||||
subpNamesOnly_ = SubprogramKind::Module;
|
||||
} else if (std::is_same_v<T, parser::InternalSubprogramPart>) {
|
||||
subpNamesOnly_ = SubprogramKind::Internal;
|
||||
} else {
|
||||
static_assert("unexpected type");
|
||||
}
|
||||
Walk(*subpPart);
|
||||
subpNamesOnly_ = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Scope *currScope_{nullptr};
|
||||
};
|
||||
|
||||
class ModuleVisitor : public virtual ScopeHandler {
|
||||
public:
|
||||
bool Pre(const parser::Module &);
|
||||
void Post(const parser::Module &);
|
||||
bool Pre(const parser::Submodule &);
|
||||
void Post(const parser::Submodule &);
|
||||
bool Pre(const parser::AccessStmt &);
|
||||
bool Pre(const parser::Only &);
|
||||
bool Pre(const parser::Rename::Names &);
|
||||
|
@ -547,6 +520,10 @@ public:
|
|||
bool Pre(const parser::UseStmt &);
|
||||
void Post(const parser::UseStmt &);
|
||||
|
||||
void BeginModule(const parser::Name &, bool isSubmodule);
|
||||
bool BeginSubmodule(const parser::Name &, const parser::ParentIdentifier &);
|
||||
void ApplyDefaultAccess();
|
||||
|
||||
private:
|
||||
// The default access spec for this module.
|
||||
Attr defaultAccess_{Attr::PUBLIC};
|
||||
|
@ -556,7 +533,6 @@ private:
|
|||
const Scope *useModuleScope_{nullptr};
|
||||
|
||||
Symbol &SetAccess(const SourceName &, Attr);
|
||||
void ApplyDefaultAccess();
|
||||
void AddUse(const parser::Rename::Names &);
|
||||
void AddUse(const parser::Rename::Operators &);
|
||||
Symbol *AddUse(const SourceName &);
|
||||
|
@ -568,8 +544,6 @@ private:
|
|||
// Record a use from useModuleScope_ of use Name/Symbol as local Name/Symbol
|
||||
SymbolRename AddUse(const SourceName &localName, const SourceName &useName);
|
||||
void AddUse(const SourceName &, Symbol &localSymbol, const Symbol &useSymbol);
|
||||
Symbol &BeginModule(const parser::Name &, bool isSubmodule,
|
||||
const std::optional<parser::ModuleSubprogramPart> &);
|
||||
Scope *FindModule(const parser::Name &, Scope *ancestor = nullptr);
|
||||
};
|
||||
|
||||
|
@ -611,20 +585,18 @@ public:
|
|||
void Post(const parser::SubroutineStmt &);
|
||||
bool Pre(const parser::FunctionStmt &);
|
||||
void Post(const parser::FunctionStmt &);
|
||||
bool Pre(const parser::SubroutineSubprogram &);
|
||||
void Post(const parser::SubroutineSubprogram &);
|
||||
bool Pre(const parser::FunctionSubprogram &);
|
||||
void Post(const parser::FunctionSubprogram &);
|
||||
bool Pre(const parser::InterfaceBody::Subroutine &);
|
||||
void Post(const parser::InterfaceBody::Subroutine &);
|
||||
bool Pre(const parser::InterfaceBody::Function &);
|
||||
void Post(const parser::InterfaceBody::Function &);
|
||||
bool Pre(const parser::SeparateModuleSubprogram &);
|
||||
void Post(const parser::SeparateModuleSubprogram &);
|
||||
bool Pre(const parser::Suffix &);
|
||||
bool Pre(const parser::PrefixSpec &);
|
||||
void Post(const parser::ImplicitPart &);
|
||||
|
||||
bool BeginSubprogram(
|
||||
const parser::Name &, Symbol::Flag, bool hasModulePrefix = false);
|
||||
void EndSubprogram();
|
||||
|
||||
protected:
|
||||
// Set when we see a stmt function that is really an array element assignment
|
||||
bool badStmtFuncFound_{false};
|
||||
|
@ -639,9 +611,6 @@ private:
|
|||
const SourceName *source{nullptr};
|
||||
} funcInfo_;
|
||||
|
||||
bool BeginSubprogram(const parser::Name &, Symbol::Flag, bool hasModulePrefix,
|
||||
const std::optional<parser::InternalSubprogramPart> &);
|
||||
void EndSubprogram();
|
||||
// Create a subprogram symbol in the current scope and push a new scope.
|
||||
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag);
|
||||
Symbol *GetSpecificFromGeneric(const parser::Name &);
|
||||
|
@ -1002,8 +971,6 @@ public:
|
|||
template<typename T> void Post(const T &) {}
|
||||
|
||||
void Post(const parser::SpecificationPart &);
|
||||
bool Pre(const parser::MainProgram &);
|
||||
void Post(const parser::EndProgramStmt &);
|
||||
void Post(const parser::Program &);
|
||||
bool Pre(const parser::ImplicitStmt &);
|
||||
void Post(const parser::PointerObject &);
|
||||
|
@ -1018,6 +985,16 @@ public:
|
|||
void Post(const parser::TypeGuardStmt &);
|
||||
bool Pre(const parser::StmtFunctionStmt &);
|
||||
bool Pre(const parser::DefinedOpName &);
|
||||
bool Pre(const parser::ProgramUnit &);
|
||||
|
||||
// These nodes should never be reached: they are handled in ProgramUnit
|
||||
bool Pre(const parser::MainProgram &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::FunctionSubprogram &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::SubroutineSubprogram &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::SeparateModuleSubprogram &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::Module &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::Submodule &) { DIE("unreachable"); }
|
||||
bool Pre(const parser::BlockData &) { DIE("unreachable"); }
|
||||
|
||||
private:
|
||||
// Kind of procedure we are expecting to see in a ProcedureDesignator
|
||||
|
@ -1029,6 +1006,10 @@ private:
|
|||
void HandleCall(Symbol::Flag, const parser::Call &);
|
||||
void HandleProcedureName(Symbol::Flag, const parser::Name &);
|
||||
bool SetProcFlag(const parser::Name &, Symbol &, Symbol::Flag);
|
||||
void ResolveExecutionParts(const ProgramTree &);
|
||||
void AddSubpNames(const ProgramTree &);
|
||||
bool BeginScope(const ProgramTree &);
|
||||
void ResolveSpecificationParts(ProgramTree &);
|
||||
};
|
||||
|
||||
// ImplicitRules implementation
|
||||
|
@ -1573,7 +1554,10 @@ void ScopeHandler::PopScope() {
|
|||
auto &symbol{*pair.second};
|
||||
ConvertToObjectEntity(symbol); // if not a proc by now, it is an object
|
||||
}
|
||||
currScope_ = &currScope_->parent();
|
||||
SetScope(currScope_->parent());
|
||||
}
|
||||
void ScopeHandler::SetScope(Scope &scope) {
|
||||
currScope_ = &scope;
|
||||
ImplicitRulesVisitor::SetScope(InclusiveScope());
|
||||
}
|
||||
|
||||
|
@ -1891,11 +1875,8 @@ void ModuleVisitor::AddUse(
|
|||
}
|
||||
}
|
||||
|
||||
bool ModuleVisitor::Pre(const parser::Submodule &x) {
|
||||
auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
|
||||
auto &name{std::get<parser::Name>(stmt.statement.t)};
|
||||
auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
|
||||
auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
|
||||
bool ModuleVisitor::BeginSubmodule(
|
||||
const parser::Name &name, const parser::ParentIdentifier &parentId) {
|
||||
auto &ancestorName{std::get<parser::Name>(parentId.t)};
|
||||
auto &parentName{std::get<std::optional<parser::Name>>(parentId.t)};
|
||||
Scope *ancestor{FindModule(ancestorName)};
|
||||
|
@ -1907,38 +1888,20 @@ bool ModuleVisitor::Pre(const parser::Submodule &x) {
|
|||
return false;
|
||||
}
|
||||
PushScope(*parentScope); // submodule is hosted in parent
|
||||
BeginModule(name, true, subpPart);
|
||||
BeginModule(name, true);
|
||||
if (!ancestor->AddSubmodule(name.source, currScope())) {
|
||||
Say(name, "Module '%s' already has a submodule named '%s'"_err_en_US,
|
||||
ancestorName.source, name.source);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void ModuleVisitor::Post(const parser::Submodule &) { ClearScopes(); }
|
||||
|
||||
bool ModuleVisitor::Pre(const parser::Module &x) {
|
||||
// Make a symbol and push a scope for this module
|
||||
const auto &name{
|
||||
std::get<parser::Statement<parser::ModuleStmt>>(x.t).statement.v};
|
||||
auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
|
||||
BeginModule(name, false, subpPart);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModuleVisitor::Post(const parser::Module &) {
|
||||
ApplyDefaultAccess();
|
||||
PopScope();
|
||||
prevAccessStmt_ = nullptr;
|
||||
}
|
||||
|
||||
Symbol &ModuleVisitor::BeginModule(const parser::Name &name, bool isSubmodule,
|
||||
const std::optional<parser::ModuleSubprogramPart> &subpPart) {
|
||||
void ModuleVisitor::BeginModule(const parser::Name &name, bool isSubmodule) {
|
||||
auto &symbol{MakeSymbol(name, ModuleDetails{isSubmodule})};
|
||||
auto &details{symbol.get<ModuleDetails>()};
|
||||
PushScope(Scope::Kind::Module, &symbol);
|
||||
details.set_scope(&currScope());
|
||||
WalkSubprogramPart(subpPart);
|
||||
return symbol;
|
||||
prevAccessStmt_ = nullptr;
|
||||
}
|
||||
|
||||
// Find a module or submodule by name and return its scope.
|
||||
|
@ -2243,49 +2206,10 @@ void SubprogramVisitor::Post(const parser::ImplicitPart &) {
|
|||
funcInfo_ = {};
|
||||
}
|
||||
|
||||
bool HasModulePrefix(const std::list<parser::PrefixSpec> &prefixes) {
|
||||
for (const auto &prefix : prefixes) {
|
||||
if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool SubprogramVisitor::Pre(const parser::SubroutineSubprogram &x) {
|
||||
const auto &stmt{
|
||||
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement};
|
||||
bool hasModulePrefix{
|
||||
HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmt.t))};
|
||||
const auto &name{std::get<parser::Name>(stmt.t)};
|
||||
const auto &subpPart{
|
||||
std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
|
||||
return BeginSubprogram(
|
||||
name, Symbol::Flag::Subroutine, hasModulePrefix, subpPart);
|
||||
}
|
||||
void SubprogramVisitor::Post(const parser::SubroutineSubprogram &) {
|
||||
EndSubprogram();
|
||||
}
|
||||
|
||||
bool SubprogramVisitor::Pre(const parser::FunctionSubprogram &x) {
|
||||
const auto &stmt{
|
||||
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement};
|
||||
bool hasModulePrefix{
|
||||
HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmt.t))};
|
||||
const auto &name{std::get<parser::Name>(stmt.t)};
|
||||
const auto &subpPart{
|
||||
std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
|
||||
return BeginSubprogram(
|
||||
name, Symbol::Flag::Function, hasModulePrefix, subpPart);
|
||||
}
|
||||
void SubprogramVisitor::Post(const parser::FunctionSubprogram &) {
|
||||
EndSubprogram();
|
||||
}
|
||||
|
||||
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Subroutine &x) {
|
||||
const auto &name{std::get<parser::Name>(
|
||||
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t)};
|
||||
return BeginSubprogram(name, Symbol::Flag::Subroutine,
|
||||
/*hasModulePrefix*/ false, std::nullopt);
|
||||
return BeginSubprogram(name, Symbol::Flag::Subroutine);
|
||||
}
|
||||
void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &) {
|
||||
EndSubprogram();
|
||||
|
@ -2293,8 +2217,7 @@ void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &) {
|
|||
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Function &x) {
|
||||
const auto &name{std::get<parser::Name>(
|
||||
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t)};
|
||||
return BeginSubprogram(
|
||||
name, Symbol::Flag::Function, /*hasModulePrefix*/ false, std::nullopt);
|
||||
return BeginSubprogram(name, Symbol::Flag::Function);
|
||||
}
|
||||
void SubprogramVisitor::Post(const parser::InterfaceBody::Function &) {
|
||||
EndSubprogram();
|
||||
|
@ -2352,14 +2275,8 @@ SubprogramDetails &SubprogramVisitor::PostSubprogramStmt(
|
|||
return symbol.get<SubprogramDetails>();
|
||||
}
|
||||
|
||||
bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
|
||||
Symbol::Flag subpFlag, bool hasModulePrefix,
|
||||
const std::optional<parser::InternalSubprogramPart> &subpPart) {
|
||||
if (subpNamesOnly_) {
|
||||
auto &symbol{MakeSymbol(name, SubprogramNameDetails{*subpNamesOnly_})};
|
||||
symbol.set(subpFlag);
|
||||
return false;
|
||||
}
|
||||
bool SubprogramVisitor::BeginSubprogram(
|
||||
const parser::Name &name, Symbol::Flag subpFlag, bool hasModulePrefix) {
|
||||
if (hasModulePrefix && !inInterfaceBlock()) {
|
||||
auto *symbol{FindSymbol(name)};
|
||||
if (!symbol || !symbol->IsSeparateModuleProc()) {
|
||||
|
@ -2375,30 +2292,9 @@ bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
|
|||
} else {
|
||||
PushSubprogramScope(name, subpFlag);
|
||||
}
|
||||
WalkSubprogramPart(subpPart);
|
||||
return true;
|
||||
}
|
||||
void SubprogramVisitor::EndSubprogram() {
|
||||
if (!subpNamesOnly_) {
|
||||
PopScope();
|
||||
}
|
||||
}
|
||||
|
||||
bool SubprogramVisitor::Pre(const parser::SeparateModuleSubprogram &x) {
|
||||
if (subpNamesOnly_) {
|
||||
return false;
|
||||
}
|
||||
const auto &name{
|
||||
std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t).statement.v};
|
||||
const auto &subpPart{
|
||||
std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
|
||||
return BeginSubprogram(
|
||||
name, Symbol::Flag::Subroutine, /*hasModulePrefix*/ true, subpPart);
|
||||
}
|
||||
|
||||
void SubprogramVisitor::Post(const parser::SeparateModuleSubprogram &) {
|
||||
EndSubprogram();
|
||||
}
|
||||
void SubprogramVisitor::EndSubprogram() { PopScope(); }
|
||||
|
||||
Symbol &SubprogramVisitor::PushSubprogramScope(
|
||||
const parser::Name &name, Symbol::Flag subpFlag) {
|
||||
|
@ -4495,6 +4391,9 @@ bool ResolveNamesVisitor::SetProcFlag(
|
|||
if (flag == Symbol::Flag::Function) {
|
||||
ApplyImplicitRules(symbol);
|
||||
}
|
||||
} else if (symbol.GetType() != nullptr && flag == Symbol::Flag::Subroutine) {
|
||||
SayWithDecl(
|
||||
name, symbol, "Cannot call function '%s' like a subroutine"_err_en_US);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -4619,20 +4518,6 @@ void ResolveNamesVisitor::CheckImport(
|
|||
}
|
||||
}
|
||||
|
||||
bool ResolveNamesVisitor::Pre(const parser::MainProgram &x) {
|
||||
using stmtType = std::optional<parser::Statement<parser::ProgramStmt>>;
|
||||
Symbol *symbol{nullptr};
|
||||
if (auto &stmt{std::get<stmtType>(x.t)}) {
|
||||
symbol = &MakeSymbol(stmt->statement.v, MainProgramDetails{});
|
||||
}
|
||||
PushScope(Scope::Kind::MainProgram, symbol);
|
||||
auto &subpPart{std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
|
||||
WalkSubprogramPart(subpPart);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResolveNamesVisitor::Post(const parser::EndProgramStmt &) { PopScope(); }
|
||||
|
||||
bool ResolveNamesVisitor::Pre(const parser::ImplicitStmt &x) {
|
||||
return CheckNotInBlock("IMPLICIT") && ImplicitRulesVisitor::Pre(x);
|
||||
}
|
||||
|
@ -4712,6 +4597,80 @@ bool ResolveNamesVisitor::Pre(const parser::DefinedOpName &x) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
|
||||
auto root{ProgramTree::Build(x)};
|
||||
SetScope(context().globalScope());
|
||||
ResolveSpecificationParts(root);
|
||||
SetScope(context().globalScope());
|
||||
ResolveExecutionParts(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the scope tree and resolve names in the specification parts of this
|
||||
// node and its children
|
||||
void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
|
||||
if (!BeginScope(node)) {
|
||||
return; // an error prevented scope from being created
|
||||
}
|
||||
Scope &scope{currScope()};
|
||||
node.set_scope(scope);
|
||||
AddSubpNames(node);
|
||||
std::visit([&](const auto *x) { Walk(*x); }, node.stmt());
|
||||
Walk(node.spec());
|
||||
if (node.IsModule()) {
|
||||
ApplyDefaultAccess();
|
||||
}
|
||||
for (auto &child : node.children()) {
|
||||
ResolveSpecificationParts(child);
|
||||
}
|
||||
PopScope();
|
||||
}
|
||||
|
||||
// Add SubprogramNameDetails symbols for contained subprograms
|
||||
void ResolveNamesVisitor::AddSubpNames(const ProgramTree &node) {
|
||||
auto kind{
|
||||
node.IsModule() ? SubprogramKind::Module : SubprogramKind::Internal};
|
||||
for (const auto &child : node.children()) {
|
||||
auto &symbol{MakeSymbol(child.name(), SubprogramNameDetails{kind})};
|
||||
symbol.set(child.GetSubpFlag());
|
||||
}
|
||||
}
|
||||
|
||||
// Push a new scope for this node or return false on error.
|
||||
bool ResolveNamesVisitor::BeginScope(const ProgramTree &node) {
|
||||
switch (node.GetKind()) {
|
||||
case ProgramTree::Kind::Program:
|
||||
PushScope(Scope::Kind::MainProgram,
|
||||
&MakeSymbol(node.name(), MainProgramDetails{}));
|
||||
return true;
|
||||
case ProgramTree::Kind::Function:
|
||||
case ProgramTree::Kind::Subroutine:
|
||||
return BeginSubprogram(
|
||||
node.name(), node.GetSubpFlag(), node.HasModulePrefix());
|
||||
case ProgramTree::Kind::MpSubprogram:
|
||||
return BeginSubprogram(
|
||||
node.name(), Symbol::Flag::Subroutine, /*hasModulePrefix*/ true);
|
||||
case ProgramTree::Kind::Module: BeginModule(node.name(), false); return true;
|
||||
case ProgramTree::Kind::Submodule:
|
||||
return BeginSubmodule(node.name(), node.GetParentId());
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve names in the execution part of this node and its children
|
||||
void ResolveNamesVisitor::ResolveExecutionParts(const ProgramTree &node) {
|
||||
if (!node.scope()) {
|
||||
return; // error occurred creating scope
|
||||
}
|
||||
SetScope(*node.scope());
|
||||
if (const auto *exec{node.exec()}) {
|
||||
Walk(*exec);
|
||||
}
|
||||
for (const auto &child : node.children()) {
|
||||
ResolveExecutionParts(child);
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveNamesVisitor::Post(const parser::Program &) {
|
||||
// ensure that all temps were deallocated
|
||||
CHECK(!attrs_);
|
||||
|
|
|
@ -488,7 +488,8 @@ static void DumpUniqueName(std::ostream &os, const Scope &scope) {
|
|||
if (scope.kind() != Scope::Kind::Global) {
|
||||
DumpUniqueName(os, scope.parent());
|
||||
os << '/';
|
||||
if (auto *scopeSymbol{scope.symbol()}) {
|
||||
if (auto *scopeSymbol{scope.symbol()};
|
||||
scopeSymbol && !scopeSymbol->name().empty()) {
|
||||
os << scopeSymbol->name();
|
||||
} else {
|
||||
int index{1};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
! Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
! Copyright (c) 2018-2019, 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.
|
||||
|
@ -49,6 +49,7 @@ module m2
|
|||
module integer function fun1()
|
||||
end function
|
||||
end interface
|
||||
!ERROR: 't' is already declared in this scoping unit
|
||||
type t
|
||||
end type
|
||||
!ERROR: Declaration of 'i' conflicts with its use as module procedure
|
||||
|
|
|
@ -40,7 +40,7 @@ contains
|
|||
!REF: /m/s/y
|
||||
!REF: /m/x
|
||||
y = x
|
||||
!DEF: /m/s/s Subprogram
|
||||
!DEF: /m/s/s PUBLIC Subprogram
|
||||
call s
|
||||
contains
|
||||
!DEF: /m/s/s2 Subprogram
|
||||
|
|
|
@ -119,3 +119,29 @@ subroutine s4
|
|||
y%a = 0.0
|
||||
end associate
|
||||
end subroutine
|
||||
|
||||
!DEF: /s5 Subprogram
|
||||
subroutine s5
|
||||
!DEF: /s5/t DerivedType
|
||||
type :: t
|
||||
!DEF: /s5/t/a ObjectEntity REAL(4)
|
||||
real :: a
|
||||
end type
|
||||
!DEF: /s5/b ObjectEntity REAL(4)
|
||||
real b
|
||||
!DEF: /s5/Block1/x AssocEntity TYPE(t)
|
||||
!DEF: /s5/f Subprogram TYPE(t)
|
||||
associate(x => f())
|
||||
!REF: /s5/b
|
||||
!REF: /s5/Block1/x
|
||||
!REF: /s5/t/a
|
||||
b = x%a
|
||||
end associate
|
||||
contains
|
||||
!DEF: /s5/f/f ObjectEntity TYPE(t)
|
||||
function f()
|
||||
!REF: /s5/t
|
||||
!REF: /s5/f/f
|
||||
type(t) :: f
|
||||
end function
|
||||
end subroutine
|
||||
|
|
Loading…
Reference in New Issue