diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -52,6 +52,7 @@ using MessageFormattedText = parser::MessageFormattedText; class ResolveNamesVisitor; +class ScopeHandler; // ImplicitRules maps initial character of identifier to the DeclTypeSpec // representing the implicit type; std::nullopt if none. @@ -320,6 +321,18 @@ void Post(const parser::TypeGuardStmt &); void Post(const parser::TypeSpec &); + // Walk the parse tree of a type spec and return the DeclTypeSpec for it. + template + const DeclTypeSpec *ProcessTypeSpec(const T &x, bool allowForward = false) { + auto restorer{common::ScopedSet(state_, State{})}; + set_allowForwardReferenceToDerivedType(allowForward); + BeginDeclTypeSpec(); + Walk(x); + const auto *type{GetDeclTypeSpec()}; + EndDeclTypeSpec(); + return type; + } + protected: struct State { bool expectDeclTypeSpec{false}; // should see decl-type-spec only when true @@ -338,18 +351,6 @@ state_.allowForwardReferenceToDerivedType = yes; } - // Walk the parse tree of a type spec and return the DeclTypeSpec for it. - template - const DeclTypeSpec *ProcessTypeSpec(const T &x, bool allowForward = false) { - auto restorer{common::ScopedSet(state_, State{})}; - set_allowForwardReferenceToDerivedType(allowForward); - BeginDeclTypeSpec(); - Walk(x); - const auto *type{GetDeclTypeSpec()}; - EndDeclTypeSpec(); - return type; - } - const DeclTypeSpec *GetDeclTypeSpec(); void BeginDeclTypeSpec(); void EndDeclTypeSpec(); @@ -450,6 +451,42 @@ void PostAttrSpec(); }; +// Manages a stack of function result information. We defer the processing +// of a type specification that appears in the prefix of a FUNCTION statement +// until the function result variable appears in the specification part +// or the end of the specification part. This allows for forward references +// in the type specification to resolve to local names. +class FuncResultStack { +public: + explicit FuncResultStack(ScopeHandler &scopeHandler) + : scopeHandler_{scopeHandler} {} + ~FuncResultStack(); + + struct FuncInfo { + // Parse tree of the type specification in the FUNCTION prefix + const parser::DeclarationTypeSpec *parsedType{nullptr}; + // Name of the function RESULT in the FUNCTION suffix, if any + const parser::Name *resultName{nullptr}; + // Result symbol + Symbol *resultSymbol{nullptr}; + std::optional source; + bool inFunctionStmt{false}; // true between Pre/Post of FunctionStmt + }; + + // Completes the definition of the top function's result. + void CompleteFunctionResultType(); + // Completes the definition of a symbol if it is the top function's result. + void CompleteTypeIfFunctionResult(Symbol &); + + FuncInfo *Top() { return stack_.empty() ? nullptr : &stack_.back(); } + FuncInfo &Push() { return stack_.emplace_back(); } + void Pop() { stack_.pop_back(); } + +private: + ScopeHandler &scopeHandler_; + std::vector stack_; +}; + // Manage a stack of Scopes class ScopeHandler : public ImplicitRulesVisitor { public: @@ -587,6 +624,8 @@ void MakeExternal(Symbol &); protected: + FuncResultStack &funcResultStack() { return funcResultStack_; } + // Apply the implicit type rules to this symbol. void ApplyImplicitRules(Symbol &, bool allowForwardReference = false); bool ImplicitlyTypeForwardRef(Symbol &); @@ -630,6 +669,7 @@ private: Scope *currScope_{nullptr}; + FuncResultStack funcResultStack_{*this}; }; class ModuleVisitor : public virtual ScopeHandler { @@ -746,7 +786,6 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor { public: - ~SubprogramVisitor(); bool HandleStmtFunction(const parser::StmtFunctionStmt &); bool Pre(const parser::SubroutineStmt &); void Post(const parser::SubroutineStmt &); @@ -768,22 +807,10 @@ void EndSubprogram(); protected: - void FinishFunctionResult(); // Set when we see a stmt function that is really an array element assignment bool badStmtFuncFound_{false}; private: - // Info about the current function: parse tree of the type in the PrefixSpec; - // name and symbol of the function result from the Suffix; source location. - struct FuncInfo { - const parser::DeclarationTypeSpec *parsedType{nullptr}; - const parser::Name *resultName{nullptr}; - Symbol *resultSymbol{nullptr}; - std::optional source; - bool inFunctionStmt{false}; // true between Pre/Post of FunctionStmt - }; - std::vector funcInfoStack_; - // Edits an existing symbol created for earlier calls to a subprogram or ENTRY // so that it can be replaced by a later definition. bool HandlePreviousCalls(const parser::Name &, Symbol &, Symbol::Flag); @@ -1967,6 +1994,37 @@ } } +// FuncResultStack implementation + +FuncResultStack::~FuncResultStack() { CHECK(stack_.empty()); } + +void FuncResultStack::CompleteFunctionResultType() { + // If the function has a type in the prefix, process it now. + if (IsFunction(scopeHandler_.currScope())) { + FuncInfo &info{DEREF(Top())}; + if (info.parsedType) { + scopeHandler_.messageHandler().set_currStmtSource(info.source); + if (const auto *type{ + scopeHandler_.ProcessTypeSpec(*info.parsedType, true)}) { + if (!scopeHandler_.context().HasError(info.resultSymbol)) { + info.resultSymbol->SetType(*type); + } + } + info.parsedType = nullptr; + } + } +} + +// Called from ConvertTo{Object/Proc}Entity to cope with any appearance +// of the function result in a specification expression. +void FuncResultStack::CompleteTypeIfFunctionResult(Symbol &symbol) { + if (FuncInfo * info{Top()}) { + if (info->resultSymbol == &symbol) { + CompleteFunctionResultType(); + } + } +} + // ScopeHandler implementation void ScopeHandler::SayAlreadyDeclared(const parser::Name &name, Symbol &prev) { @@ -2224,6 +2282,7 @@ void ScopeHandler::ApplyImplicitRules( Symbol &symbol, bool allowForwardReference) { + funcResultStack_.CompleteTypeIfFunctionResult(symbol); if (context().HasError(symbol) || !NeedsType(symbol)) { return; } @@ -2332,6 +2391,7 @@ } else if (symbol.has()) { symbol.set_details(ObjectEntityDetails{}); } else if (auto *details{symbol.detailsIf()}) { + funcResultStack_.CompleteTypeIfFunctionResult(symbol); symbol.set_details(ObjectEntityDetails{std::move(*details)}); } else if (auto *useDetails{symbol.detailsIf()}) { return useDetails->symbol().has(); @@ -2347,6 +2407,7 @@ } else if (symbol.has()) { symbol.set_details(ProcEntityDetails{}); } else if (auto *details{symbol.detailsIf()}) { + funcResultStack_.CompleteTypeIfFunctionResult(symbol); symbol.set_details(ProcEntityDetails{std::move(*details)}); if (symbol.GetType() && !symbol.test(Symbol::Flag::Implicit)) { CHECK(!symbol.test(Symbol::Flag::Subroutine)); @@ -3027,8 +3088,6 @@ // SubprogramVisitor implementation -SubprogramVisitor::~SubprogramVisitor() { CHECK(funcInfoStack_.empty()); } - // Return false if it is actually an assignment statement. bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) { const auto &name{std::get(x.t)}; @@ -3085,10 +3144,9 @@ bool SubprogramVisitor::Pre(const parser::Suffix &suffix) { if (suffix.resultName) { if (IsFunction(currScope())) { - if (!funcInfoStack_.empty()) { - FuncInfo &info{funcInfoStack_.back()}; - if (info.inFunctionStmt) { - info.resultName = &suffix.resultName.value(); + if (FuncResultStack::FuncInfo * info{funcResultStack().Top()}) { + if (info->inFunctionStmt) { + info->resultName = &suffix.resultName.value(); } else { // will check the result name in Post(EntryStmt) } @@ -3107,8 +3165,7 @@ bool SubprogramVisitor::Pre(const parser::PrefixSpec &x) { // Save this to process after UseStmt and ImplicitPart if (const auto *parsedType{std::get_if(&x.u)}) { - CHECK(!funcInfoStack_.empty()); - FuncInfo &info{funcInfoStack_.back()}; + FuncResultStack::FuncInfo &info{DEREF(funcResultStack().Top())}; if (info.parsedType) { // C1543 Say(currStmtSource().value(), "FUNCTION prefix cannot specify the type more than once"_err_en_US); @@ -3123,23 +3180,6 @@ } } -void SubprogramVisitor::FinishFunctionResult() { - // If the function has a type in the prefix, process it now. - if (IsFunction(currScope())) { - CHECK(!funcInfoStack_.empty()); - FuncInfo &info{funcInfoStack_.back()}; - if (info.parsedType) { - messageHandler().set_currStmtSource(info.source); - if (const auto *type{ProcessTypeSpec(*info.parsedType, true)}) { - if (!context().HasError(info.resultSymbol)) { - info.resultSymbol->SetType(*type); - } - } - info.parsedType = nullptr; - } - } -} - bool SubprogramVisitor::Pre(const parser::InterfaceBody::Subroutine &x) { const auto &name{std::get( std::get>(x.t).statement.t)}; @@ -3161,8 +3201,7 @@ return BeginAttrs(); } bool SubprogramVisitor::Pre(const parser::FunctionStmt &) { - CHECK(!funcInfoStack_.empty()); - FuncInfo &info{funcInfoStack_.back()}; + FuncResultStack::FuncInfo &info{DEREF(funcResultStack().Top())}; CHECK(!info.inFunctionStmt); info.inFunctionStmt = true; return BeginAttrs(); @@ -3190,8 +3229,7 @@ details.add_dummyArg(dummy); } const parser::Name *funcResultName; - CHECK(!funcInfoStack_.empty()); - FuncInfo &info{funcInfoStack_.back()}; + FuncResultStack::FuncInfo &info{DEREF(funcResultStack().Top())}; CHECK(info.inFunctionStmt); info.inFunctionStmt = false; if (info.resultName && info.resultName->source != name.source) { @@ -3208,9 +3246,9 @@ // add function result to function scope EntityDetails funcResultDetails; funcResultDetails.set_funcResult(true); - funcInfoStack_.back().resultSymbol = - &MakeSymbol(*funcResultName, std::move(funcResultDetails)); - details.set_result(*funcInfoStack_.back().resultSymbol); + Symbol &result{MakeSymbol(*funcResultName, std::move(funcResultDetails))}; + info.resultSymbol = &result; + details.set_result(result); } // C1560. if (info.resultName && info.resultName->source == name.source) { @@ -3229,14 +3267,6 @@ // Clear the RESULT() name now in case an ENTRY statement in the implicit-part // has a RESULT() suffix. info.resultName = nullptr; - // If there was a type on the function statement, and it is an intrinsic - // type, process that type now so that inquiries in specification expressions - // will work. Derived types are deferred to the end of the specification part - // so that they can resolve to a locally declared type. - if (info.parsedType && - std::holds_alternative(info.parsedType->u)) { - FinishFunctionResult(); - } } SubprogramDetails &SubprogramVisitor::PostSubprogramStmt( @@ -3408,7 +3438,7 @@ SetScope(DEREF(symbol->scope())); symbol->get().set_isInterface(false); if (IsFunction(*symbol)) { - funcInfoStack_.emplace_back(); // just to be popped later + funcResultStack().Push(); // just to be popped later } } else { // Copy the interface into a new subprogram scope. @@ -3427,7 +3457,7 @@ if (details.isFunction()) { currScope().erase(symbol->name()); newDetails.set_result(*currScope().CopySymbol(details.result())); - funcInfoStack_.emplace_back(); // just to be popped later + funcResultStack().Push(); // just to be popped later } } return true; @@ -3471,14 +3501,14 @@ } } if (IsFunction(currScope())) { - funcInfoStack_.emplace_back(); + funcResultStack().Push(); } return true; } void SubprogramVisitor::EndSubprogram() { if (IsFunction(currScope())) { - funcInfoStack_.pop_back(); + funcResultStack().Pop(); } PopScope(); } @@ -3868,7 +3898,7 @@ HandleAttributeStmt(Attr::EXTERNAL, x.v); for (const auto &name : x.v) { auto *symbol{FindSymbol(name)}; - if (!ConvertToProcEntity(*symbol)) { + if (!ConvertToProcEntity(DEREF(symbol))) { SayWithDecl( name, *symbol, "EXTERNAL attribute not allowed on '%s'"_err_en_US); } else if (symbol->attrs().test(Attr::INTRINSIC)) { // C840 @@ -6873,7 +6903,7 @@ void ResolveNamesVisitor::FinishSpecificationPart( const std::list &decls) { badStmtFuncFound_ = false; - FinishFunctionResult(); + funcResultStack().CompleteFunctionResultType(); CheckImports(); bool inModule{currScope().kind() == Scope::Kind::Module}; for (auto &pair : currScope()) { diff --git a/flang/test/Semantics/resolve108.f90 b/flang/test/Semantics/resolve108.f90 --- a/flang/test/Semantics/resolve108.f90 +++ b/flang/test/Semantics/resolve108.f90 @@ -45,25 +45,27 @@ !If we got the type of foo right, this declaration will fail !due to an attempted division by zero. !ERROR: Must be a constant value - integer, parameter :: test = 1 / (kind(foo(1)) - kind(1.e0)) + integer, parameter :: test = 1 / (kind(foo(1)) - kind(1.d0)) end subroutine module m3 - integer, parameter :: k = kind(1.e0) + real(kind=kind(1.0e0)) :: x contains real(kind=kind(x)) function foo(x) - !ERROR: The type of 'x' has already been implicitly declared real(kind=kind(1.0d0)) x + !ERROR: Must be a constant value + integer, parameter :: test = 1 / (kind(foo) - kind(1.d0)) foo = n end function end module module m4 contains - !ERROR: Must be a constant value real(n) function foo(x) + !ERROR: 'foo' is not an object that can appear in an expression integer, parameter :: n = kind(foo) real(n), intent(in) :: x + !ERROR: 'x' is not an object that can appear in an expression foo = x end function end module