diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -96,6 +96,12 @@ bool InFunction() const { return innermostSymbol_ && IsFunction(*innermostSymbol_); } + bool InInterface() const { + const SubprogramDetails *subp{innermostSymbol_ + ? innermostSymbol_->detailsIf() + : nullptr}; + return subp && subp->isInterface(); + } template void SayWithDeclaration(const Symbol &symbol, A &&...x) { if (parser::Message * msg{messages_.Say(std::forward(x)...)}) { @@ -247,16 +253,37 @@ CheckPointer(symbol); } if (InPure()) { - if (IsSaved(symbol)) { - if (IsInitialized(symbol)) { - messages_.Say( - "A pure subprogram may not initialize a variable"_err_en_US); - } else { - messages_.Say( - "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US); + if (InInterface()) { + // Declarations in interface definitions "have no effect" if they + // are not pertinent to the characteristics of the procedure. + // Restrictions on entities in pure procedure interfaces don't need + // enforcement. + } else { + if (IsSaved(symbol)) { + if (IsInitialized(symbol)) { + messages_.Say( + "A pure subprogram may not initialize a variable"_err_en_US); + } else { + messages_.Say( + "A pure subprogram may not have a variable with the SAVE attribute"_err_en_US); + } + } + if (!IsDummy(symbol) && !IsFunctionResult(symbol)) { + if (IsPolymorphicAllocatable(symbol)) { + SayWithDeclaration(symbol, + "Deallocation of polymorphic object '%s' is not permitted in a pure subprogram"_err_en_US, + symbol.name()); + } else if (derived) { + if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { + SayWithDeclaration(*bad, + "Deallocation of polymorphic object '%s%s' is not permitted in a pure subprogram"_err_en_US, + symbol.name(), bad.BuildResultDesignatorName()); + } + } } } - if (symbol.attrs().test(Attr::VOLATILE)) { + if (symbol.attrs().test(Attr::VOLATILE) && + (IsDummy(symbol) || !InInterface())) { messages_.Say( "A pure subprogram may not have a variable with the VOLATILE attribute"_err_en_US); } @@ -264,19 +291,6 @@ messages_.Say( "A dummy procedure of a pure subprogram must be pure"_err_en_US); } - if (!IsDummy(symbol) && !IsFunctionResult(symbol)) { - if (IsPolymorphicAllocatable(symbol)) { - SayWithDeclaration(symbol, - "Deallocation of polymorphic object '%s' is not permitted in a pure subprogram"_err_en_US, - symbol.name()); - } else if (derived) { - if (auto bad{FindPolymorphicAllocatableUltimateComponent(*derived)}) { - SayWithDeclaration(*bad, - "Deallocation of polymorphic object '%s%s' is not permitted in a pure subprogram"_err_en_US, - symbol.name(), bad.BuildResultDesignatorName()); - } - } - } } if (type) { // Section 7.2, paragraph 7 bool canHaveAssumedParameter{IsNamedConstant(symbol) || diff --git a/flang/test/Semantics/call10.f90 b/flang/test/Semantics/call10.f90 --- a/flang/test/Semantics/call10.f90 +++ b/flang/test/Semantics/call10.f90 @@ -17,6 +17,25 @@ real, volatile, target :: volatile + interface + ! Ensure no errors for "ignored" declarations in a pure interface. + ! These declarations do not contribute to the characteristics of + ! the procedure and must not elicit spurious errors about being used + ! in a pure procedure. + pure subroutine s05a + import polyAlloc + real, save :: v1 + real :: v2 = 0. + real :: v3 + data v3/0./ + real :: v4 + common /blk/ v4 + save /blk/ + type(polyAlloc) :: v5 + real, volatile :: v6 + end subroutine + end interface + contains subroutine impure(x)