This is an archive of the discontinued LLVM Phabricator instance.

[flang] Add one semantic check for allocatable/pointer argument association
ClosedPublic

Authored by peixin on Mar 30 2022, 7:18 PM.

Details

Summary

The actual argument shall have deferred the same type parameters as
the dummy argument if the argument is allocatable or pointer variable.
Currently programs not following this get one crash during execution.

Diff Detail

Event Timeline

peixin created this revision.Mar 30 2022, 7:18 PM
Herald added a project: Restricted Project. · View Herald TranscriptMar 30 2022, 7:18 PM
Herald added a subscriber: jdoerfert. · View Herald Transcript
peixin requested review of this revision.Mar 30 2022, 7:18 PM

If a dummy argument is allocatable, the associated actual argument must be one whole array, not array section or substring.

Actually, I don't find this in F2018 standard. Gfortran and ifort report semantic errors for this. F18 in fir-dev crash during lowering to FIR/MLIR. First, in semantics, passing partial heap seems not reasonable. Second, for FIR lowering, it seems passing a box cannot support parital heap. For a box of ptr, it is ok.

This restriction does not applies to pointer. Check the following example,

program main
  character(:), pointer :: s
  character(5), target :: t = "abcde"
  integer, pointer :: x(:)
  integer, target :: y(5) = 2

  s=>t
  x=>y
  call sub(s(1:2))
  call sub2(x(1:2))
contains
  subroutine sub(ptr)
    character(len=:), pointer, intent(in) :: ptr
    print *, ptr
  end
  subroutine sub2(ptr)
    integer, pointer, intent(in) :: ptr(:)
    print *, ptr
  end
end

This works ok in gfortran, ifort and LLVM Flang in fir-dev. The open-source classic-flang does not support it and I think nvfortran does not, either. This case is used in workload FPM. So it should be ok.

jeanPerier requested changes to this revision.Mar 31 2022, 1:52 AM

Looks better thanks. The second added error message might still be redundant in some cases, and I dot need you need to add the first one if you fix the determination of the actualIsAllocatable boolean, which I think should be done. See more details inlined.

If a dummy argument is allocatable, the associated actual argument must be one whole array, not array section or substring.

Actually, I don't find this in F2018 standard. Gfortran and ifort report semantic errors for this.

The actual constraint is that if the dummy has the ALLOCATABLE attribute, the actual argument shall be allocatable ( see Fortran 2018 15.5.2.6 point 2 about allocatable dummy variables). It happens that the subojects of allocatable variables are not themselves allocatables (See the NOTE 2 in Fortran 2018 section 9.5.3 NOTE 2: Unless otherwise specified, an array element or array section does not have an attribute of the whole array. In particular, an array element or an array section does not have the POINTER or ALLOCATABLE attribute.). So passing an a section of an allocatable to an allocatable violates 15.5.2.6 point 2.

Regarding pointers, your test is valid because the dummy pointer is INTENT(IN), but if the INTENT(IN) attribute was not present, this would be a violation of Fortran 2018 15.5.2.7 point 2. Flang is already enforcing this correctly though, so you do not need to update anything here.

flang/lib/Semantics/check-call.cpp
410

The issue lies in actualIsAllocatable that is wrong just above, it assumes the actual is a whole symbol. A boolean actualIsAllocatable should not be true for an actual argument like an_allocatable(:) because an_allocatable(:) is not an allocatable.

Instead, actualIsAllocatable should be determined by a more generic infrastructure like evaluate::IsAllocatable(actual). It seems we do not have that yet, and I really think we should.
It would probably require adding a new evaluate::UnwrapWholeSymbolOrComponentOrCoarrayRef to include/Evaluate/tools.h so that you can use it in evaluate::IsAllocatable. If you want, I can add evaluate::IsAllocatable for you, just let me know.

493

For parametrized derived type, this check will be redundant with the one above (line 486 where you added the Standard ref).

module test
  type t(l)
    integer, len :: l
    character(l) :: c
  end type
contains
  subroutine bar(p)
    type(t(:)), allocatable :: p(:)
  end subroutine
  subroutine foo
    type(t(10)), allocatable :: p(:)
    call bar(p)
  end subroutine
end module

Could you move it as an else if of `if (const auto *derived{

evaluate::GetDerivedTypeSpec(actualType.type())}) {` line 487 ? to restrict this message to characters and avoid the duplication ?
flang/test/Lower/allocatable-caller.f90
93

Could you transform that into:

test_char_array_explicit_call(n)
    integer :: n
    ....
    character(n), allocatable :: x2(:)
    ...
    test_char_array_explicit(x2)

That way, we can test that lowering insert the type cast when needed.

flang/test/Lower/pointer-args-caller.f90
51

Can you update this to being:

subroutine test_ptr_to_non_deferred_char_array_ptr(p, n)
   integer :: n
   character(n), pointer :: p(:)
   call non_deferred_char_array_ptr(p)
end subroutine

So that we have a test that passes a non deferred length pointer to another non deferred length pointer ?

This revision now requires changes to proceed.Mar 31 2022, 1:52 AM

Regarding pointers, your test is valid because the dummy pointer is INTENT(IN), but if the INTENT(IN) attribute was not present, this would be a violation of Fortran 2018 15.5.2.7 point 2. Flang is already enforcing this correctly though, so you do not need to update anything here.

Got it. Thanks for this. This is pointer association, not argument association.

flang/lib/Semantics/check-call.cpp
410

It would probably require adding a new evaluate::UnwrapWholeSymbolOrComponentOrCoarrayRef to include/Evaluate/tools.h so that you can use it in evaluate::IsAllocatable. If you want, I can add evaluate::IsAllocatable for you, just let me know.

Agree, adding these two sounds more resonable to me. Please add it as you want. I am really grateful.

493

Sure. Will also add this test case.

flang/test/Lower/allocatable-caller.f90
93

Sure, will change this.

flang/test/Lower/pointer-args-caller.f90
51

Sure, will change this.

peixin updated this revision to Diff 419688.Apr 1 2022, 2:46 AM
peixin edited the summary of this revision. (Show Details)

Addressed all the comments and fix the summary. Waiting for @jeanPerier 's new functions to override checking if one symbol is allocatable.

Waiting for @jeanPerier 's new functions to override checking if one symbol is allocatable.

New helper for review in: https://reviews.llvm.org/D122899

peixin updated this revision to Diff 419907.Apr 1 2022, 7:06 PM
peixin retitled this revision from [flang] Add some semantic checks for allocatable/pointer argument association to [flang] Add one semantic check for allocatable/pointer argument association.
peixin edited the summary of this revision. (Show Details)

Remove the IsAllocatableDesignator check.

jeanPerier accepted this revision.Apr 4 2022, 12:32 AM

Thanks @peixin, LGTM.

This revision is now accepted and ready to land.Apr 4 2022, 12:32 AM