[flang] Process specification parts before execution parts
authorTim Keith <tkeith@nvidia.com>
Mon, 6 May 2019 14:26:43 +0000 (07:26 -0700)
committerTim Keith <tkeith@nvidia.com>
Mon, 6 May 2019 14:26:43 +0000 (07:26 -0700)
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@20e803fd9289759a4e421794bdb9b401ee709da2
Reviewed-on: https://github.com/flang-compiler/f18/pull/443
Tree-same-pre-rewrite: false

flang/lib/semantics/resolve-names-utils.cc
flang/lib/semantics/resolve-names-utils.h
flang/lib/semantics/resolve-names.cc
flang/lib/semantics/symbol.cc
flang/test/semantics/resolve36.f90
flang/test/semantics/symbol02.f90
flang/test/semantics/symbol11.f90

index 2199cc26be00d6eae1dc2e68df50656df0ad3161..0b186bbc06ff8d8cc0f3b41772895ab10ef9200a 100644 (file)
@@ -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));
+}
+
 }
index 60259ef3f8f86d56fb9e17a26c8c2a9f08a7a51d..c55e6bfe82ac8f59f97de75b7c81ca68bf60dec5 100644 (file)
 #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_
index 53649833a337a84d41c65ca2149e1c377c3c4f82..5246ad87ed11cff53acbc8ad43cdcdb1ec07e52e 100644 (file)
@@ -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_);
index edb6637286a916ed9ea3e2e7a38eb7d1b53670c8..d779ce66d269db596cf126b193585db98a8e87f2 100644 (file)
@@ -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};
index 52683ec902199a8616dacb4af2af325a73d8bf50..6fa99e558db309b2c2e45d98d8a8ab6cf58c7d35 100644 (file)
@@ -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
index abeb969805bc15f115ab4184dc135d0743300b2c..db2e83f528c09aae9dba178b101ba6b712d9c918 100644 (file)
@@ -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
index 43f123fd6ec199d313e3e4d283e8b2a11be6ee8d..b1055561bb32c6a4e65b403346b1b53d67a7e31d 100644 (file)
@@ -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