peter klausler 452d7ebc09 [flang] Ensure that intrinsic procedures are PURE &/or ELEMENTAL
The intrinsic procedure table properly classify the various
intrinsics, but the PURE and ELEMENTAL attributes that these
classifications imply don't always make it to the utility
predicates that test symbols for them, leading to spurious
error messages in some contexts.  So set those attribute flags
as appropriate in name resolution, using a new function to
isolate the tests.

An alternate solution, in which the predicates would query
the intrinsic procedure table for these attributes on demand,
was something I also tried, so that this information could
come directly from an authoritative source; but it would have
required references to the intrinsic table to be passed along
on too many seemingly unrelated APIs and ended up looking messy.

Several symbol table tests needed to have their expected outputs
augmented with the PURE and ELEMENTAL flags.  Some bogus messages
that were flagged as such in test/Semantics/doconcurrent01.f90 were
removed, since they are now correctly not emitted.

Differential Revision: https://reviews.llvm.org/D96878
2021-02-17 11:31:33 -08:00

98 lines
2.7 KiB
Fortran

! RUN: %S/test_errors.sh %s %t %f18
! Test 15.7 C1591 & others: contexts requiring pure subprograms
module m
type :: t
contains
procedure, nopass :: tbp_pure => pure
procedure, nopass :: tbp_impure => impure
end type
type, extends(t) :: t2
contains
!ERROR: An overridden pure type-bound procedure binding must also be pure
procedure, nopass :: tbp_pure => impure ! 7.5.7.3
end type
contains
pure integer function pure(n)
integer, value :: n
pure = n
end function
impure integer function impure(n)
integer, value :: n
impure = n
end function
subroutine test
real :: a(pure(1)) ! ok
!ERROR: Invalid specification expression: reference to impure function 'impure'
real :: b(impure(1)) ! 10.1.11(4)
forall (j=1:1)
!ERROR: Impure procedure 'impure' may not be referenced in a FORALL
a(j) = impure(j) ! C1037
end forall
forall (j=1:1)
!ERROR: Impure procedure 'impure' may not be referenced in a FORALL
a(j) = pure(impure(j)) ! C1037
end forall
!ERROR: DO CONCURRENT mask expression may not reference impure procedure 'impure'
do concurrent (j=1:1, impure(j) /= 0) ! C1121
!ERROR: Call to an impure procedure is not allowed in DO CONCURRENT
a(j) = impure(j) ! C1139
end do
end subroutine
subroutine test2
type(t) :: x
real :: a(x%tbp_pure(1)) ! ok
!ERROR: Invalid specification expression: reference to impure function 'impure'
real :: b(x%tbp_impure(1))
forall (j=1:1)
a(j) = x%tbp_pure(j) ! ok
end forall
forall (j=1:1)
!ERROR: Impure procedure 'impure' may not be referenced in a FORALL
a(j) = x%tbp_impure(j) ! C1037
end forall
do concurrent (j=1:1, x%tbp_pure(j) /= 0) ! ok
a(j) = x%tbp_pure(j) ! ok
end do
!ERROR: DO CONCURRENT mask expression may not reference impure procedure 'impure'
do concurrent (j=1:1, x%tbp_impure(j) /= 0) ! C1121
!ERROR: Call to an impure procedure component is not allowed in DO CONCURRENT
a(j) = x%tbp_impure(j) ! C1139
end do
end subroutine
subroutine test3
type :: t
integer :: i
end type
type(t) :: a(10), b
forall (i=1:10)
a(i) = t(pure(i)) ! OK
end forall
forall (i=1:10)
!ERROR: Impure procedure 'impure' may not be referenced in a FORALL
a(i) = t(impure(i)) ! C1037
end forall
end subroutine
subroutine test4(ch)
type :: t
real, allocatable :: x
end type
type(t) :: a(1), b(1)
character(*), intent(in) :: ch
allocate (b(1)%x)
! Intrinsic functions and a couple subroutines are pure; do not emit errors
do concurrent (j=1:1)
b(j)%x = cos(1.) + len(ch)
call move_alloc(from=b(j)%x, to=a(j)%x)
end do
end subroutine
end module