Jean Perier 47995a0ec9 [flang] catch implicit interface incompatibility with global scope symbol
Previously, when calling a procedure implicitly for which a global scope
procedure symbol with the same name existed, semantics resolved the
procedure name in the call to the global symbol without checking that
the symbol interface was compatible with the implicit interface of the
call.
This could cause expression rewrite and lowering to later badly process
the implicit call assuming a different result type or an explicit
interface. This could lead to lowering crash in case the actual argument
were incompatible with the dummies from the explicit interface.

Emit errors in the following problematic cases:
- If the result type from the symbol did not match the one from the
  implicit interface.
- If the symbol requires an explicit interface.

This patch still allows calling an F77 like procedure with different
actual argument types than the one it was defined with because it is
correctly supported in lowering and is a feature in some program
(it is a pointer cast). The two cases that won't be accepted have
little chance to make much sense. Results returning ABIs may differ
depending on the return types, and function that requires explicit
interface usually requires descriptors or specific processing that
is incompatible with implicit interfaces.

Note that this patch is not making a deep analysis, and it will only
catch mistakes if a global symbol and an implicit interface are
involved. Cases where the user provided a conflicting explicit
interface would still require a pass after name resolution to study
conflicts more deeply. But these cases will not crash lowering or
trigger expression rewrite to do weird things.

Differential Revision: https://reviews.llvm.org/D119274
2022-02-09 09:30:32 +01:00

157 lines
7.9 KiB
Fortran

! RUN: %python %S/test_errors.py %s %flang_fc1
! C750 Each bound in the explicit-shape-spec shall be a specification
! expression in which there are no references to specification functions or
! the intrinsic functions ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, PRESENT,
! or SAME_TYPE_AS, every specification inquiry reference is a constant
! expression, and the value does not depend on the value of a variable.
!
! C754 Each type-param-value within a component-def-stmt shall be a colon or
! a specification expression in which there are no references to specification
! functions or the intrinsic functions ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF,
! PRESENT, or SAME_TYPE_AS, every specification inquiry reference is a
! constant expression, and the value does not depend on the value of a variable.
impure function impureFunc()
integer :: impureFunc
impureFunc = 3
end function impureFunc
pure function iPureFunc()
integer :: iPureFunc
iPureFunc = 3
end function iPureFunc
module m
real, allocatable :: mVar
end module m
subroutine s(iArg, allocArg, pointerArg, arrayArg, ioArg, optionalArg)
! C750
use m
implicit logical(l)
integer, intent(in) :: iArg
real, allocatable, intent(in) :: allocArg
real, pointer, intent(in) :: pointerArg
integer, dimension(:), intent(in) :: arrayArg
integer, intent(inout) :: ioArg
real, optional, intent(in) :: optionalArg
! These declarations are OK since they're not in a derived type
real :: realVar
real, volatile :: volatileVar
real, dimension(merge(1, 2, allocated(allocArg))) :: realVar1
real, dimension(merge(1, 2, associated(pointerArg))) :: realVar2
real, dimension(merge(1, 2, is_contiguous(arrayArg))) :: realVar3
real, dimension(ioArg) :: realVar4
real, dimension(merge(1, 2, present(optionalArg))) :: realVar5
! statement functions referenced below
iVolatileStmtFunc() = 3 * volatileVar
iImpureStmtFunc() = 3 * impureFunc()
iPureStmtFunc() = 3 * iPureFunc()
! This is OK
real, dimension(merge(1, 2, allocated(mVar))) :: rVar
integer :: var = 3
!ERROR: Invalid specification expression: reference to impure function 'ivolatilestmtfunc'
real, dimension(iVolatileStmtFunc()) :: arrayVarWithVolatile
!ERROR: Invalid specification expression: reference to impure function 'iimpurestmtfunc'
real, dimension(iImpureStmtFunc()) :: arrayVarWithImpureFunction
!ERROR: Invalid specification expression: reference to statement function 'ipurestmtfunc'
real, dimension(iPureStmtFunc()) :: arrayVarWithPureFunction
real, dimension(iabs(iArg)) :: arrayVarWithIntrinsic
type arrayType
!ERROR: Invalid specification expression: derived type component or type parameter value not allowed to reference variable 'var'
real, dimension(var) :: varField
!ERROR: Invalid specification expression: reference to impure function 'ivolatilestmtfunc'
real, dimension(iVolatileStmtFunc()) :: arrayFieldWithVolatile
!ERROR: Invalid specification expression: reference to impure function 'iimpurestmtfunc'
real, dimension(iImpureStmtFunc()) :: arrayFieldWithImpureFunction
!ERROR: Invalid specification expression: reference to statement function 'ipurestmtfunc'
real, dimension(iPureStmtFunc()) :: arrayFieldWithPureFunction
!ERROR: Invalid specification expression: derived type component or type parameter value not allowed to reference variable 'iarg'
real, dimension(iabs(iArg)) :: arrayFieldWithIntrinsic
!ERROR: Invalid specification expression: reference to intrinsic 'allocated' not allowed for derived type components or type parameter values
real, dimension(merge(1, 2, allocated(allocArg))) :: realField1
!ERROR: Invalid specification expression: reference to intrinsic 'associated' not allowed for derived type components or type parameter values
real, dimension(merge(1, 2, associated(pointerArg))) :: realField2
!ERROR: Invalid specification expression: non-constant reference to inquiry intrinsic 'is_contiguous' not allowed for derived type components or type parameter values
real, dimension(merge(1, 2, is_contiguous(arrayArg))) :: realField3
!ERROR: Invalid specification expression: derived type component or type parameter value not allowed to reference variable 'ioarg'
real, dimension(ioArg) :: realField4
!ERROR: Invalid specification expression: reference to intrinsic 'present' not allowed for derived type components or type parameter values
real, dimension(merge(1, 2, present(optionalArg))) :: realField5
end type arrayType
end subroutine s
subroutine s1()
! C750, check for a constant specification inquiry that's a type parameter
! inquiry which are defined in 9.4.5
type derived(kindParam, lenParam)
integer, kind :: kindParam = 3
integer, len :: lenParam = 3
end type
contains
subroutine inner (derivedArg)
type(derived), intent(in), dimension(3) :: derivedArg
integer :: localInt
type(derived), parameter :: localderived = derived()
type localDerivedType
! OK because the specification inquiry is a constant
integer, dimension(localDerived%kindParam) :: goodField
! OK because the value of lenParam is constant in this context
integer, dimension(derivedArg%lenParam) :: badField
end type localDerivedType
! OK because we're not defining a component
integer, dimension(derivedArg%kindParam) :: localVar
end subroutine inner
end subroutine s1
subroutine s2(iArg, allocArg, pointerArg, arrayArg, optionalArg)
! C754
integer, intent(in) :: iArg
real, allocatable, intent(in) :: allocArg
real, pointer, intent(in) :: pointerArg
integer, dimension(:), intent(in) :: arrayArg
real, optional, intent(in) :: optionalArg
type paramType(lenParam)
integer, len :: lenParam = 4
end type paramType
type charType
!ERROR: Invalid specification expression: derived type component or type parameter value not allowed to reference variable 'iarg'
character(iabs(iArg)) :: fieldWithIntrinsic
!ERROR: Invalid specification expression: reference to intrinsic 'allocated' not allowed for derived type components or type parameter values
character(merge(1, 2, allocated(allocArg))) :: allocField
!ERROR: Invalid specification expression: reference to intrinsic 'associated' not allowed for derived type components or type parameter values
character(merge(1, 2, associated(pointerArg))) :: assocField
!ERROR: Invalid specification expression: non-constant reference to inquiry intrinsic 'is_contiguous' not allowed for derived type components or type parameter values
character(merge(1, 2, is_contiguous(arrayArg))) :: contigField
!ERROR: Invalid specification expression: reference to intrinsic 'present' not allowed for derived type components or type parameter values
character(merge(1, 2, present(optionalArg))) :: presentField
end type charType
type derivedType
!ERROR: Invalid specification expression: derived type component or type parameter value not allowed to reference variable 'iarg'
type(paramType(iabs(iArg))) :: fieldWithIntrinsic
!ERROR: Invalid specification expression: reference to intrinsic 'allocated' not allowed for derived type components or type parameter values
type(paramType(merge(1, 2, allocated(allocArg)))) :: allocField
!ERROR: Invalid specification expression: reference to intrinsic 'associated' not allowed for derived type components or type parameter values
type(paramType(merge(1, 2, associated(pointerArg)))) :: assocField
!ERROR: Invalid specification expression: non-constant reference to inquiry intrinsic 'is_contiguous' not allowed for derived type components or type parameter values
type(paramType(merge(1, 2, is_contiguous(arrayArg)))) :: contigField
!ERROR: Invalid specification expression: reference to intrinsic 'present' not allowed for derived type components or type parameter values
type(paramType(merge(1, 2, present(optionalArg)))) :: presentField
end type derivedType
end subroutine s2