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.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
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.
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 | ||
---|---|---|
407 | 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. | |
490 | 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 ? |
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 | ||
---|---|---|
407 |
Agree, adding these two sounds more resonable to me. Please add it as you want. I am really grateful. | |
490 | 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. |
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
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.