From cab9b3072bcae1f998de75e0e59870d489648833 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 4 Jun 2019 13:35:59 -0700 Subject: [PATCH] [flang] Skim executable parts to detect dummy procedure calls 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 | 64 +++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/flang/lib/semantics/resolve-names.cc b/flang/lib/semantics/resolve-names.cc index bc5aee9..462898d 100644 --- a/flang/lib/semantics/resolve-names.cc +++ b/flang/lib/semantics/resolve-names.cc @@ -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 bool Pre(const A &) { return true; } + template 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(call.t)}; + if (const auto *name{std::get_if(&designator.u)}) { + if (Symbol * symbol{scope_.FindSymbol(name->source)}) { + if (auto *details{symbol->detailsIf()}) { + 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()}) { 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()); } -- 2.7.4