[flang] Skim executable parts to detect dummy procedure calls
authorpeter klausler <pklausler@nvidia.com>
Tue, 4 Jun 2019 20:35:59 +0000 (13:35 -0700)
committerpeter klausler <pklausler@nvidia.com>
Tue, 4 Jun 2019 20:37:35 +0000 (13:37 -0700)
Original-commit: flang-compiler/f18@b085255e5c8fa8e2d16b76c49beb76e005ca6060
Reviewed-on: https://github.com/flang-compiler/f18/pull/477
Tree-same-pre-rewrite: false

flang/lib/semantics/resolve-names.cc

index bc5aee9..462898d 100644 (file)
@@ -1672,7 +1672,6 @@ static bool NeedsType(const Symbol &symbol) {
   return true;
 }
 void ScopeHandler::ApplyImplicitRules(Symbol &symbol) {
-  ConvertToObjectEntity(symbol);
   if (NeedsType(symbol)) {
     if (isImplicitNoneType()) {
       Say(symbol.name(), "No explicit type declared for '%s'"_err_en_US);
@@ -3628,6 +3627,7 @@ Symbol *DeclarationVisitor::DeclareLocalEntity(const parser::Name &name) {
     // Declare the name as an object in the enclosing scope so that
     // the name can't be repurposed there later as something else.
     prev = &MakeSymbol(InclusiveScope(), name.source, Attrs{});
+    ConvertToObjectEntity(*prev);
     ApplyImplicitRules(*prev);
     implicit = true;
   }
@@ -4297,6 +4297,7 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
       return nullptr;  // reported an error
     }
     if (symbol->IsDummy()) {
+      ConvertToObjectEntity(*symbol);
       ApplyImplicitRules(*symbol);
     }
     return &name;
@@ -4313,6 +4314,7 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
         "'%s' from host scoping unit is not accessible due to IMPORT"_err_en_US);
     return nullptr;
   }
+  ConvertToObjectEntity(*symbol);
   ApplyImplicitRules(*symbol);
   return &name;
 }
@@ -4669,6 +4671,51 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
   return false;
 }
 
+// Calls to dummy procedures need to record that their symbols are known
+// to be procedures, so that they don't get converted to objects by default.
+class ExecutionPartSkimmer {
+public:
+  ExecutionPartSkimmer(SemanticsContext &c, Scope &s)
+    : context_{c}, scope_{s} {}
+
+  void Walk(const parser::ExecutionPart *exec) {
+    if (exec != nullptr) {
+      parser::Walk(*exec, *this);
+    }
+  }
+
+  template<typename A> bool Pre(const A &) { return true; }
+  template<typename A> void Post(const A &) {}
+  void Post(const parser::FunctionReference &fr) {
+    NoteCall(Symbol::Flag::Function, fr.v);
+  }
+  void Post(const parser::CallStmt &cs) {
+    NoteCall(Symbol::Flag::Subroutine, cs.v);
+  }
+
+private:
+  void NoteCall(Symbol::Flag, const parser::Call &);
+
+  SemanticsContext &context_;
+  Scope &scope_;
+};
+
+void ExecutionPartSkimmer::NoteCall(
+    Symbol::Flag flag, const parser::Call &call) {
+  auto &designator{std::get<parser::ProcedureDesignator>(call.t)};
+  if (const auto *name{std::get_if<parser::Name>(&designator.u)}) {
+    if (Symbol * symbol{scope_.FindSymbol(name->source)}) {
+      if (auto *details{symbol->detailsIf<EntityDetails>()}) {
+        if (details->isDummy()) {
+          symbol->set_details(ProcEntityDetails{std::move(*details)});
+          symbol->set(flag);
+          symbol->attrs().set(Attr::EXTERNAL);
+        }
+      }
+    }
+  }
+}
+
 // Build the scope tree and resolve names in the specification parts of this
 // node and its children
 void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
@@ -4683,14 +4730,6 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
   if (node.IsModule()) {
     ApplyDefaultAccess();
   }
-  for (auto &child : node.children()) {
-    ResolveSpecificationParts(child);
-  }
-  // Subtlety: PopScope() is not called here because we want to defer
-  // conversions of uncategorized entities into objects until after
-  // we have traversed the executable part of the subprogram.
-  // Function results, however, are converted now so that they can
-  // be used in executable parts.
   if (Symbol * symbol{currScope().symbol()}) {
     if (auto *details{symbol->detailsIf<SubprogramDetails>()}) {
       if (details->isFunction()) {
@@ -4699,6 +4738,13 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
       }
     }
   }
+  ExecutionPartSkimmer{context(), scope}.Walk(node.exec());
+  for (auto &child : node.children()) {
+    ResolveSpecificationParts(child);
+  }
+  // Subtlety: PopScope() is not called here because we want to defer
+  // conversions of uncategorized entities into objects until after
+  // we have traversed the executable part of the subprogram.
   SetScope(currScope().parent());
 }