Skip to content

Commit

Permalink
[flang] Catch impure defined assignments in DO CONCURRENT
Browse files Browse the repository at this point in the history
The semantic checking of DO CONCURRENT bodies looks only at the
parse tree, not the typed expressions produced from it, so it
misses calls to defined assignment subroutines that arise from
assignment statements that resolve via generic interfaces into
subroutine calls.  Extend the checking to peek into the typed
assignment operations left on the parse tree by semantics.

Differential Revision: https://reviews.llvm.org/D146585
  • Loading branch information
klausler committed Mar 28, 2023
1 parent 30ce6fb commit b0f02ce
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 4 deletions.
18 changes: 14 additions & 4 deletions flang/lib/Semantics/check-do-forall.cpp
Expand Up @@ -219,6 +219,16 @@ class DoConcurrentBodyEnforce {
SayDeallocateWithImpureFinal(*entity, reason);
}
}
if (const auto *assignment{GetAssignment(stmt)}) {
if (const auto *call{
std::get_if<evaluate::ProcedureRef>(&assignment->u)}) {
if (auto bad{FindImpureCall(context_.foldingContext(), *call)}) {
context_.Say(currentStatementSourcePosition_,
"The defined assignment subroutine '%s' is not pure"_err_en_US,
*bad);
}
}
}
}

// Deallocation from a DEALLOCATE statement
Expand Down Expand Up @@ -431,10 +441,10 @@ class DoContext {
}

void Check(const parser::ForallAssignmentStmt &stmt) {
const evaluate::Assignment *assignment{common::visit(
common::visitors{[&](const auto &x) { return GetAssignment(x); }},
stmt.u)};
if (assignment) {
if (const evaluate::Assignment *
assignment{common::visit(
common::visitors{[&](const auto &x) { return GetAssignment(x); }},
stmt.u)}) {
CheckForallIndexesUsed(*assignment);
CheckForImpureCall(assignment->lhs);
CheckForImpureCall(assignment->rhs);
Expand Down
31 changes: 31 additions & 0 deletions flang/test/Semantics/doconcurrent01.f90
Expand Up @@ -237,3 +237,34 @@ pure integer function pureFunc()
end function pureFunc

end subroutine s7

module m8
type t
contains
procedure tbpAssign
generic :: assignment(=) => tbpAssign
end type
interface assignment(=)
module procedure nonTbpAssign
end interface
contains
impure elemental subroutine tbpAssign(to, from)
class(t), intent(out) :: to
class(t), intent(in) :: from
print *, 'impure due to I/O'
end
impure elemental subroutine nonTbpAssign(to, from)
type(t), intent(out) :: to
integer, intent(in) :: from
print *, 'impure due to I/O'
end
subroutine test
type(t) x, y
do concurrent (j=1:1)
!ERROR: The defined assignment subroutine 'tbpassign' is not pure
x = y
!ERROR: The defined assignment subroutine 'nontbpassign' is not pure
x = 666
end do
end
end

0 comments on commit b0f02ce

Please sign in to comment.