[flang] Skim executable parts to detect dummy procedure calls

Original-commit: flang-compiler/f18@b085255e5c
Reviewed-on: https://github.com/flang-compiler/f18/pull/477
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-06-04 13:35:59 -07:00
parent 0d242e2006
commit cab9b3072b

View 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());
}