Index: flang/lib/Evaluate/tools.cpp =================================================================== --- flang/lib/Evaluate/tools.cpp +++ flang/lib/Evaluate/tools.cpp @@ -1272,16 +1272,21 @@ ultimate.has()); } -bool IsPureProcedure(const Symbol &original) { +static bool IsPureProcedureImpl( + const Symbol &original, semantics::UnorderedSymbolSet &set) { // An ENTRY is pure if its containing subprogram is const Symbol &symbol{DEREF(GetMainEntry(&original.GetUltimate()))}; + if (set.find(symbol) != set.end()) { + return true; + } + set.emplace(symbol); if (const auto *procDetails{symbol.detailsIf()}) { if (procDetails->procInterface()) { // procedure with a pure interface - return IsPureProcedure(*procDetails->procInterface()); + return IsPureProcedureImpl(*procDetails->procInterface(), set); } } else if (const auto *details{symbol.detailsIf()}) { - return IsPureProcedure(details->symbol()); + return IsPureProcedureImpl(details->symbol(), set); } else if (!IsProcedure(symbol)) { return false; } @@ -1293,7 +1298,7 @@ if (&*ref == &symbol) { return false; // error recovery, recursion is caught elsewhere } - if (IsFunction(*ref) && !IsPureProcedure(*ref)) { + if (IsFunction(*ref) && !IsPureProcedureImpl(*ref, set)) { return false; } if (ref->GetUltimate().attrs().test(Attr::VOLATILE)) { @@ -1308,6 +1313,11 @@ !symbol.attrs().test(Attr::IMPURE)); } +bool IsPureProcedure(const Symbol &original) { + semantics::UnorderedSymbolSet set; + return IsPureProcedureImpl(original, set); +} + bool IsPureProcedure(const Scope &scope) { const Symbol *symbol{scope.GetSymbol()}; return symbol && IsPureProcedure(*symbol); Index: flang/test/Semantics/stmt-func01.f90 =================================================================== --- flang/test/Semantics/stmt-func01.f90 +++ flang/test/Semantics/stmt-func01.f90 @@ -34,7 +34,10 @@ integer :: sf9 !ERROR: Defining expression of statement function 'sf9' cannot be converted to its result type INTEGER(4) sf9(n) = "bad" - sf10 = 1. + !ERROR: Statement function 'sf10' may not reference another statement function 'sf11' that is defined later + sf10(n) = sf11(n) + sf11(n) = sf10(n) ! mutual recursion, caused crash + sf13 = 1. contains real function explicit(x,y) integer, intent(in) :: x @@ -47,6 +50,6 @@ end function subroutine foo !PORTABILITY: An implicitly typed statement function should not appear when the same symbol is available in its host scope - sf10(x) = 2.*x + sf13(x) = 2.*x end subroutine end