[flang] Defer stmt function body analysis until specification part complete

Expression analysis was being invoked on the bodies of statement functions
as they were being encountered during name resolution.  This led to failures
on some FCVS tests in cases where those expressions contained implicitly
typed objects.  Defer the analysis of statemet function bodies to the end
of the specification part, at which time the symbols of the enclosing scope
will have been typed.

Reviewed By: tskeith

Differential Revision: https://reviews.llvm.org/D82796
This commit is contained in:
peter klausler 2020-06-29 10:45:02 -07:00
parent 5918d49ac1
commit f45b41348b
1 changed files with 28 additions and 10 deletions

View File

@ -1436,7 +1436,7 @@ private:
void PreSpecificationConstruct(const parser::SpecificationConstruct &);
void CreateGeneric(const parser::GenericSpec &);
void FinishSpecificationPart();
void FinishSpecificationPart(const std::list<parser::DeclarationConstruct> &);
void CheckImports();
void CheckImport(const SourceName &, const SourceName &);
void HandleCall(Symbol::Flag, const parser::Call &);
@ -2714,11 +2714,9 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
details.set_result(result);
const auto &parsedExpr{std::get<parser::Scalar<parser::Expr>>(x.t)};
Walk(parsedExpr);
if (auto expr{AnalyzeExpr(context(), parsedExpr)}) {
details.set_stmtFunction(std::move(*expr));
} else {
context().SetError(symbol);
}
// The analysis of the expression that constitutes the body of the
// statement function is deferred to FinishSpecificationPart() so that
// all declarations and implicit typing are complete.
PopScope();
return true;
}
@ -6011,7 +6009,7 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
}
}
Walk(decls);
FinishSpecificationPart();
FinishSpecificationPart(decls);
return false;
}
@ -6068,7 +6066,8 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
info.Resolve(&MakeSymbol(symbolName, Attrs{}, std::move(genericDetails)));
}
void ResolveNamesVisitor::FinishSpecificationPart() {
void ResolveNamesVisitor::FinishSpecificationPart(
const std::list<parser::DeclarationConstruct> &decls) {
badStmtFuncFound_ = false;
CheckImports();
bool inModule{currScope().kind() == Scope::Kind::Module};
@ -6089,6 +6088,25 @@ void ResolveNamesVisitor::FinishSpecificationPart() {
}
}
currScope().InstantiateDerivedTypes(context());
// Analyze the bodies of statement functions now that the symbol in this
// specification part have been fully declared and implicitly typed.
for (const auto &decl : decls) {
if (const auto *statement{std::get_if<
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>>(
&decl.u)}) {
const parser::StmtFunctionStmt &stmtFunc{statement->statement.value()};
if (Symbol * symbol{std::get<parser::Name>(stmtFunc.t).symbol}) {
if (auto *details{symbol->detailsIf<SubprogramDetails>()}) {
if (auto expr{AnalyzeExpr(context(),
std::get<parser::Scalar<parser::Expr>>(stmtFunc.t))}) {
details->set_stmtFunction(std::move(*expr));
} else {
context().SetError(*symbol);
}
}
}
}
}
// TODO: what about instantiations in BLOCK?
CheckSaveStmts();
CheckCommonBlocks();
@ -6278,8 +6296,8 @@ void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
node.stmt());
Walk(node.spec());
// If this is a function, convert result to an object. This is to prevent the
// result to be converted later to a function symbol if it is called inside
// the function.
// result from being converted later to a function symbol if it is called
// inside the function.
// If the result is function pointer, then ConvertToObjectEntity will not
// convert the result to an object, and calling the symbol inside the function
// will result in calls to the result pointer.