bool BeginSubprogram(const parser::Name &, Symbol::Flag,
bool hasModulePrefix = false,
- const parser::LanguageBindingSpec * = nullptr);
+ const parser::LanguageBindingSpec * = nullptr,
+ const ProgramTree::EntryStmtList * = nullptr);
bool BeginMpSubprogram(const parser::Name &);
void PushBlockDataScope(const parser::Name &);
void EndSubprogram();
entryDetails.set_entryScope(inclusiveScope);
if (inFunction) {
// Create the entity to hold the function result, if necessary.
- Symbol *resultSymbol{nullptr};
auto &effectiveResultName{*(resultName ? resultName : &name)};
- resultSymbol = FindInScope(currScope(), effectiveResultName);
+ Symbol *resultSymbol{FindInScope(currScope(), effectiveResultName)};
if (resultSymbol) { // C1574
common::visit(
- common::visitors{[](EntityDetails &x) { x.set_funcResult(true); },
+ common::visitors{[resultSymbol](UnknownDetails &) {
+ EntityDetails entity;
+ entity.set_funcResult(true);
+ resultSymbol->set_details(std::move(entity));
+ },
+ [](EntityDetails &x) { x.set_funcResult(true); },
[](ObjectEntityDetails &x) { x.set_funcResult(true); },
[](ProcEntityDetails &x) { x.set_funcResult(true); },
[&](const auto &) {
context().SetError(*resultSymbol);
}},
resultSymbol->details());
+ // The Function flag will have been set if the ENTRY's symbol was created
+ // as a placeholder in BeginSubprogram. This prevents misuse of the ENTRY
+ // as a subroutine. Clear it now because it's inappropriate for a
+ // function result.
+ resultSymbol->set(Symbol::Flag::Function, false);
} else if (!inSpecificationPart_) {
ObjectEntityDetails entity;
entity.set_funcResult(true);
// A subprogram or interface declared with SUBROUTINE or FUNCTION
bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
Symbol::Flag subpFlag, bool hasModulePrefix,
- const parser::LanguageBindingSpec *bindingSpec) {
+ const parser::LanguageBindingSpec *bindingSpec,
+ const ProgramTree::EntryStmtList *entryStmts) {
if (hasModulePrefix && currScope().IsGlobal()) { // C1547
Say(name,
"'%s' is a MODULE procedure which must be declared within a "
}
if (IsFunction(currScope())) {
funcResultStack().Push();
+ if (entryStmts) {
+ // It's possible to refer to the function result variable of an ENTRY
+ // statement that lacks an explicit RESULT in code that appears before the
+ // ENTRY. Create a placeholder symbol now for that case so that the name
+ // doesn't resolve instead to the ENTRY's symbol in the scope around the
+ // function.
+ for (const auto &ref : *entryStmts) {
+ const auto &suffix{std::get<std::optional<parser::Suffix>>(ref->t)};
+ if (!(suffix && suffix->resultName)) {
+ Symbol &symbol{MakeSymbol(std::get<parser::Name>(ref->t).source,
+ Attrs{}, UnknownDetails{})};
+ symbol.set(Symbol::Flag::Function);
+ }
+ }
+ }
}
return true;
}
case ProgramTree::Kind::Function:
case ProgramTree::Kind::Subroutine:
return BeginSubprogram(node.name(), node.GetSubpFlag(),
- node.HasModulePrefix(), node.bindingSpec());
+ node.HasModulePrefix(), node.bindingSpec(), &node.entryStmts());
case ProgramTree::Kind::MpSubprogram:
return BeginMpSubprogram(node.name());
case ProgramTree::Kind::Module: