[flang] Fix resolution of function prefix type
authorTim Keith <tkeith@nvidia.com>
Sun, 24 Feb 2019 18:05:43 +0000 (10:05 -0800)
committerGitHub <noreply@github.com>
Thu, 28 Feb 2019 18:38:17 +0000 (10:38 -0800)
When a function-stmt has a type in the prefix (`type(t) function f()`),
the type cannot be resolve until after processing the USE and IMPLICIT
statements. So save the parse-tree of the type and process it at the
end of the specification section.

Add `ProcessTypeSpec()` to handle the process of setting up to walk
a type spec, walking it, restoring the state, and returning the type
spec. We do this several other places too.

Original-commit: flang-compiler/f18@bcde294d0e62c6ef8506392f66816814ae976dff
Reviewed-on: https://github.com/flang-compiler/f18/pull/305
Tree-same-pre-rewrite: false

flang/lib/semantics/resolve-names.cc
flang/test/semantics/modfile04.f90

index 8bebe31..61be4a7 100644 (file)
@@ -280,10 +280,19 @@ protected:
     } derived;
   };
 
+  // Walk the parse tree of a type spec and return the DeclTypeSpec for it.
+  template<typename T> const DeclTypeSpec *ProcessTypeSpec(const T &x) {
+    auto save{common::ScopedSet(state_, State{})};
+    BeginDeclTypeSpec();
+    Walk(x);
+    const auto *type{GetDeclTypeSpec()};
+    EndDeclTypeSpec();
+    return type;
+  }
+
   const DeclTypeSpec *GetDeclTypeSpec();
   void BeginDeclTypeSpec();
   void EndDeclTypeSpec();
-  State SetDeclTypeSpecState(State);
   void SetDeclTypeSpec(const DeclTypeSpec &);
   void SetDeclTypeSpecCategory(DeclTypeSpec::Category);
   DeclTypeSpec::Category GetDeclTypeSpecCategory() const {
@@ -599,14 +608,22 @@ public:
   bool Pre(const parser::SeparateModuleSubprogram &);
   void Post(const parser::SeparateModuleSubprogram &);
   bool Pre(const parser::Suffix &);
+  bool Pre(const parser::PrefixSpec &);
 
 protected:
   // Set when we see a stmt function that is really an array element assignment
   bool badStmtFuncFound_{false};
+  void HandleFunctionPrefixType();
 
 private:
-  // Function result name from parser::Suffix, if any.
-  const parser::Name *funcResultName_{nullptr};
+  // Info about the current function: parse tree of the type in the PrefixSpec;
+  // name and symbol of the function result from the Suffix; source location.
+  struct {
+    const parser::DeclarationTypeSpec *parsedType{nullptr};
+    const parser::Name *resultName{nullptr};
+    Symbol *resultSymbol{nullptr};
+    const SourceName *source{nullptr};
+  } funcInfo_;
 
   bool BeginSubprogram(const parser::Name &, Symbol::Flag, bool hasModulePrefix,
       const std::optional<parser::InternalSubprogramPart> &);
@@ -949,7 +966,6 @@ public:
   template<typename T> bool Pre(const T &) { return true; }
   template<typename T> void Post(const T &) {}
 
-  bool Pre(const parser::PrefixSpec &);
   void Post(const parser::SpecificationPart &);
   bool Pre(const parser::MainProgram &);
   void Post(const parser::EndProgramStmt &);
@@ -1187,12 +1203,6 @@ void DeclTypeSpecVisitor::EndDeclTypeSpec() {
   state_ = {};
 }
 
-DeclTypeSpecVisitor::State DeclTypeSpecVisitor::SetDeclTypeSpecState(State x) {
-  auto result{state_};
-  state_ = x;
-  return result;
-}
-
 void DeclTypeSpecVisitor::SetDeclTypeSpecCategory(
     DeclTypeSpec::Category category) {
   CHECK(state_.expectDeclTypeSpec);
@@ -2168,11 +2178,28 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
 
 bool SubprogramVisitor::Pre(const parser::Suffix &suffix) {
   if (suffix.resultName) {
-    funcResultName_ = &suffix.resultName.value();
+    funcInfo_.resultName = &suffix.resultName.value();
   }
   return true;
 }
 
+bool SubprogramVisitor::Pre(const parser::PrefixSpec &x) {
+  // Save this to process after UseStmt and ImplicitPart
+  funcInfo_.parsedType = std::get_if<parser::DeclarationTypeSpec>(&x.u);
+  funcInfo_.source = currStmtSource();
+  return funcInfo_.parsedType == nullptr;
+}
+
+void SubprogramVisitor::HandleFunctionPrefixType() {
+  if (funcInfo_.parsedType) {
+    messageHandler().set_currStmtSource(funcInfo_.source);
+    if (const auto *type{ProcessTypeSpec(*funcInfo_.parsedType)}) {
+      funcInfo_.resultSymbol->SetType(*type);
+    }
+  }
+  funcInfo_ = {};
+}
+
 bool HasModulePrefix(const std::list<parser::PrefixSpec> &prefixes) {
   for (const auto &prefix : prefixes) {
     if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
@@ -2234,10 +2261,6 @@ bool SubprogramVisitor::Pre(const parser::SubroutineStmt &stmt) {
   return BeginAttrs();
 }
 bool SubprogramVisitor::Pre(const parser::FunctionStmt &stmt) {
-  if (!subpNamesOnly_) {
-    BeginDeclTypeSpec();
-    CHECK(!funcResultName_);
-  }
   return BeginAttrs();
 }
 
@@ -2259,23 +2282,18 @@ void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
     Symbol &dummy{MakeSymbol(dummyName, EntityDetails(true))};
     details.add_dummyArg(dummy);
   }
-  // add function result to function scope
-  EntityDetails funcResultDetails;
-  funcResultDetails.set_funcResult(true);
-  if (auto *type{GetDeclTypeSpec()}) {
-    funcResultDetails.set_type(*type);
-  }
-  EndDeclTypeSpec();
-
   const parser::Name *funcResultName;
-  if (funcResultName_ && funcResultName_->source != name.source) {
-    funcResultName = funcResultName_;
+  if (funcInfo_.resultName && funcInfo_.resultName->source != name.source) {
+    funcResultName = funcInfo_.resultName;
   } else {
     EraseSymbol(name);  // was added by PushSubprogramScope
     funcResultName = &name;
   }
-  details.set_result(MakeSymbol(*funcResultName, funcResultDetails));
-  funcResultName_ = nullptr;
+  // add function result to function scope
+  EntityDetails funcResultDetails;
+  funcResultDetails.set_funcResult(true);
+  funcInfo_.resultSymbol = &MakeSymbol(*funcResultName, funcResultDetails);
+  details.set_result(*funcInfo_.resultSymbol);
 }
 
 SubprogramDetails &SubprogramVisitor::PostSubprogramStmt(
@@ -3255,14 +3273,8 @@ void DeclarationVisitor::Post(const parser::AllocateStmt &) {
 }
 
 bool DeclarationVisitor::Pre(const parser::StructureConstructor &x) {
-  auto savedState{SetDeclTypeSpecState({})};
-  BeginDeclTypeSpec();
   auto &parsedType{std::get<parser::DerivedTypeSpec>(x.t)};
-  Walk(parsedType);
-  const DeclTypeSpec *type{GetDeclTypeSpec()};
-  EndDeclTypeSpec();
-  SetDeclTypeSpecState(savedState);
-
+  const DeclTypeSpec *type{ProcessTypeSpec(parsedType)};
   if (type == nullptr) {
     return false;
   }
@@ -3645,10 +3657,7 @@ Symbol *DeclarationVisitor::DeclareStatementEntity(const parser::Name &name,
     return nullptr;  // error was reported in DeclareEntity
   }
   if (type.has_value()) {
-    BeginDeclTypeSpec();
-    DeclarationVisitor::Post(*type);
-    declTypeSpec = GetDeclTypeSpec();
-    EndDeclTypeSpec();
+    declTypeSpec = ProcessTypeSpec(*type);
   }
   if (declTypeSpec != nullptr) {
     SetType(name, *declTypeSpec);
@@ -3848,12 +3857,7 @@ bool ConstructVisitor::Pre(const parser::LocalitySpec::Shared &x) {
 }
 
 bool ConstructVisitor::Pre(const parser::AcSpec &x) {
-  // AcSpec can occur within a TypeDeclarationStmt: save and restore state
-  auto savedState{SetDeclTypeSpecState({})};
-  BeginDeclTypeSpec();
-  Walk(x.type);
-  EndDeclTypeSpec();
-  SetDeclTypeSpecState(savedState);
+  ProcessTypeSpec(x.type);
   PushScope(Scope::Kind::ImpliedDos, nullptr);
   Walk(x.values);
   PopScope();
@@ -4143,10 +4147,6 @@ const DeclTypeSpec &ConstructVisitor::ToDeclTypeSpec(
 
 // ResolveNamesVisitor implementation
 
-bool ResolveNamesVisitor::Pre(const parser::PrefixSpec &x) {
-  return true;  // TODO
-}
-
 bool ResolveNamesVisitor::Pre(const parser::FunctionReference &x) {
   HandleCall(Symbol::Flag::Function, x.v);
   return false;
@@ -4474,6 +4474,7 @@ static bool NeedsExplicitType(const Symbol &symbol) {
 void ResolveNamesVisitor::Post(const parser::SpecificationPart &) {
   badStmtFuncFound_ = false;
   CheckImports();
+  HandleFunctionPrefixType();
   bool inModule{currScope().kind() == Scope::Kind::Module};
   for (auto &pair : currScope()) {
     auto &symbol{*pair.second};
index 539c598..2b82e39 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.
@@ -14,7 +14,9 @@
 
 ! modfile with subprograms
 
-module m
+module m1
+  type :: t
+  end type
 contains
 
   pure subroutine s(x, y) bind(c)
@@ -34,8 +36,20 @@ contains
 
 end
 
-!Expect: m.mod
-!module m
+module m2
+contains
+  type(t) function f3()
+    use m1
+  end
+  function f4() result(x)
+    implicit complex(x)
+  end
+end
+
+!Expect: m1.mod
+!module m1
+!type::t
+!end type
 !contains
 !pure subroutine s(x,y) bind(c)
 !logical(4),intent(in)::x
@@ -49,3 +63,14 @@ end
 !complex(4)::y
 !end
 !end
+
+!Expect: m2.mod
+!module m2
+!contains
+!function f3()
+!type(t)::f3
+!end
+!function f4() result(x)
+!complex(4)::x
+!end
+!end