[flang] Refine implicit typing of functions and prevent invalid conversion to objects

Original-commit: flang-compiler/f18@a90f752c20
Reviewed-on: https://github.com/flang-compiler/f18/pull/531
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-06-26 14:51:58 -07:00
parent 6c5487dfca
commit 7d33b8529a
2 changed files with 53 additions and 45 deletions

View File

@ -1039,7 +1039,7 @@ public:
bool Pre(const parser::Submodule &) { DIE("unreachable"); } bool Pre(const parser::Submodule &) { DIE("unreachable"); }
bool Pre(const parser::BlockData &) { DIE("unreachable"); } bool Pre(const parser::BlockData &) { DIE("unreachable"); }
bool SetProcFlag(const parser::Name &, Symbol &, Symbol::Flag); void NoteExecutablePartCall(Symbol::Flag, const parser::Call &);
private: private:
// Kind of procedure we are expecting to see in a ProcedureDesignator // Kind of procedure we are expecting to see in a ProcedureDesignator
@ -1050,6 +1050,7 @@ private:
void CheckImport(const SourceName &, const SourceName &); void CheckImport(const SourceName &, const SourceName &);
void HandleCall(Symbol::Flag, const parser::Call &); void HandleCall(Symbol::Flag, const parser::Call &);
void HandleProcedureName(Symbol::Flag, const parser::Name &); void HandleProcedureName(Symbol::Flag, const parser::Name &);
bool SetProcFlag(const parser::Name &, Symbol &, Symbol::Flag);
void ResolveExecutionParts(const ProgramTree &); void ResolveExecutionParts(const ProgramTree &);
void AddSubpNames(const ProgramTree &); void AddSubpNames(const ProgramTree &);
bool BeginScope(const ProgramTree &); bool BeginScope(const ProgramTree &);
@ -1682,8 +1683,10 @@ static bool NeedsType(const Symbol &symbol) {
[](const EntityDetails &) { return true; }, [](const EntityDetails &) { return true; },
[](const ObjectEntityDetails &) { return true; }, [](const ObjectEntityDetails &) { return true; },
[](const AssocEntityDetails &) { return true; }, [](const AssocEntityDetails &) { return true; },
[&](const ProcEntityDetails &) { [&](const ProcEntityDetails &p) {
return symbol.test(Symbol::Flag::Function); return symbol.test(Symbol::Flag::Function) &&
p.interface().type() == nullptr &&
p.interface().symbol() == nullptr;
}, },
[](const auto &) { return false; }, [](const auto &) { return false; },
}, },
@ -3977,19 +3980,21 @@ bool ConstructVisitor::Pre(const parser::LocalitySpec::LocalInit &x) {
} }
bool ConstructVisitor::Pre(const parser::LocalitySpec::Shared &x) { bool ConstructVisitor::Pre(const parser::LocalitySpec::Shared &x) {
for (const auto &name : x.v) { for (auto &name : x.v) {
auto *prev{FindSymbol(name)}; if (auto *prev{FindSymbol(name)}) {
if (!prev) { if (prev->owner() == currScope()) {
SayAlreadyDeclared(name, *prev); // C1125 & C1126
} else if (!IsVariableName(*prev)) {
SayBadLocality(name, *prev); // C1124
} else {
auto &symbol{MakeSymbol(name, HostAssocDetails{*prev})};
symbol.set(Symbol::Flag::LocalityShared);
name.symbol = &symbol; // override resolution to parent
}
} else {
Say(name, "Variable '%s' not found"_err_en_US); Say(name, "Variable '%s' not found"_err_en_US);
context().SetError( context().SetError(
MakeSymbol(name, ObjectEntityDetails{EntityDetails{}})); MakeSymbol(name, ObjectEntityDetails{EntityDetails{}}));
} else if (prev->owner() == currScope()) {
SayAlreadyDeclared(name, *prev); // C1125 and C1126
} else if (!IsVariableName(*prev)) {
SayBadLocality(name, *prev); // C1124
} else {
auto &symbol{MakeSymbol(name, HostAssocDetails{*prev})};
symbol.set(Symbol::Flag::LocalityShared);
} }
} }
return false; return false;
@ -4606,16 +4611,13 @@ void ResolveNamesVisitor::HandleProcedureName(
if (!symbol->has<ProcEntityDetails>()) { if (!symbol->has<ProcEntityDetails>()) {
ConvertToProcEntity(*symbol); ConvertToProcEntity(*symbol);
} }
if (const auto type{GetImplicitType(*symbol)}) {
symbol->get<ProcEntityDetails>().interface().set_type(*type);
}
SetProcFlag(name, *symbol, flag); SetProcFlag(name, *symbol, flag);
} else if (symbol->has<UnknownDetails>()) { } else if (symbol->has<UnknownDetails>()) {
CHECK(!"unexpected UnknownDetails"); CHECK(!"unexpected UnknownDetails");
} else if (CheckUseError(name)) { } else if (CheckUseError(name)) {
// error was reported // error was reported
} else { } else {
symbol = Resolve(name, &symbol->GetUltimate()); symbol = &Resolve(name, symbol)->GetUltimate();
ConvertToProcEntity(*symbol); ConvertToProcEntity(*symbol);
if (!SetProcFlag(name, *symbol, flag)) { if (!SetProcFlag(name, *symbol, flag)) {
return; // reported error return; // reported error
@ -4635,6 +4637,32 @@ void ResolveNamesVisitor::HandleProcedureName(
} }
} }
// Variant of HandleProcedureName() for use while skimming the executable
// part of a subprogram to catch calls that might be part of the subprogram's
// interface, and to mark as procedures any symbols that might otherwise be
// miscategorized as objects.
void ResolveNamesVisitor::NoteExecutablePartCall(
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{FindSymbol(*name)}) {
Symbol::Flag other{flag == Symbol::Flag::Subroutine
? Symbol::Flag::Function
: Symbol::Flag::Subroutine};
if (!symbol->test(other)) {
ConvertToProcEntity(*symbol);
if (auto *details{symbol->detailsIf<ProcEntityDetails>()}) {
symbol->set(flag);
if (symbol->IsDummy()) {
symbol->attrs().set(Attr::EXTERNAL);
}
ApplyImplicitRules(*symbol);
}
}
}
}
}
// Check and set the Function or Subroutine flag on symbol; false on error. // Check and set the Function or Subroutine flag on symbol; false on error.
bool ResolveNamesVisitor::SetProcFlag( bool ResolveNamesVisitor::SetProcFlag(
const parser::Name &name, Symbol &symbol, Symbol::Flag flag) { const parser::Name &name, Symbol &symbol, Symbol::Flag flag) {
@ -4869,8 +4897,8 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
// to be procedures, so that they don't get converted to objects by default. // to be procedures, so that they don't get converted to objects by default.
class ExecutionPartSkimmer { class ExecutionPartSkimmer {
public: public:
ExecutionPartSkimmer(ResolveNamesVisitor &resolver, Scope &s) explicit ExecutionPartSkimmer(ResolveNamesVisitor &resolver)
: resolver_{resolver}, scope_{s} {} : resolver_{resolver} {}
void Walk(const parser::ExecutionPart *exec) { void Walk(const parser::ExecutionPart *exec) {
if (exec != nullptr) { if (exec != nullptr) {
@ -4881,36 +4909,16 @@ public:
template<typename A> bool Pre(const A &) { return true; } template<typename A> bool Pre(const A &) { return true; }
template<typename A> void Post(const A &) {} template<typename A> void Post(const A &) {}
void Post(const parser::FunctionReference &fr) { void Post(const parser::FunctionReference &fr) {
NoteCall(Symbol::Flag::Function, fr.v); resolver_.NoteExecutablePartCall(Symbol::Flag::Function, fr.v);
} }
void Post(const parser::CallStmt &cs) { void Post(const parser::CallStmt &cs) {
NoteCall(Symbol::Flag::Subroutine, cs.v); resolver_.NoteExecutablePartCall(Symbol::Flag::Subroutine, cs.v);
} }
private: private:
void NoteCall(Symbol::Flag, const parser::Call &);
ResolveNamesVisitor &resolver_; ResolveNamesVisitor &resolver_;
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 (resolver_.SetProcFlag(*name, *symbol, flag)) {
symbol->set_details(ProcEntityDetails{std::move(*details)});
if (symbol->IsDummy()) {
symbol->attrs().set(Attr::EXTERNAL);
}
}
}
}
}
}
// Build the scope tree and resolve names in the specification parts of this // Build the scope tree and resolve names in the specification parts of this
// node and its children // node and its children
void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) { void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
@ -4928,9 +4936,9 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
for (auto &child : node.children()) { for (auto &child : node.children()) {
ResolveSpecificationParts(child); ResolveSpecificationParts(child);
} }
ExecutionPartSkimmer{*this, scope}.Walk(node.exec()); ExecutionPartSkimmer{*this}.Walk(node.exec());
PopScope(); PopScope();
// Ensure every object and function entity has a type. // Ensure that every object entity has a type.
for (auto &pair : *node.scope()) { for (auto &pair : *node.scope()) {
ApplyImplicitRules(*pair.second); ApplyImplicitRules(*pair.second);
} }

View File

@ -120,9 +120,9 @@ subroutine s6
!DEF: /s6/Block1/i ObjectEntity INTEGER(4) !DEF: /s6/Block1/i ObjectEntity INTEGER(4)
!DEF: /s6/Block1/j (local) ObjectEntity INTEGER(8) !DEF: /s6/Block1/j (local) ObjectEntity INTEGER(8)
!DEF: /s6/Block1/k (implicit) (local_init) ObjectEntity INTEGER(4) !DEF: /s6/Block1/k (implicit) (local_init) ObjectEntity INTEGER(4)
!REF: /s6/a
do concurrent(integer::i=1:5)local(j)local_init(k)shared(a)
!DEF: /s6/Block1/a (shared) HostAssoc !DEF: /s6/Block1/a (shared) HostAssoc
do concurrent(integer::i=1:5)local(j)local_init(k)shared(a)
!REF: /s6/a
!REF: /s6/Block1/i !REF: /s6/Block1/i
!REF: /s6/Block1/j !REF: /s6/Block1/j
a(i) = j+1 a(i) = j+1