llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.33k stars 12.12k forks source link

[Flang] Incorrect diagnose on NULL(mold) actual to allocatable dummy #115984

Open DanielCChen opened 2 weeks ago

DanielCChen commented 2 weeks ago

Consider the following code:

module m
    type Base
        integer i
    end type

    type, extends(Base) :: Child
        integer j
    end type
end module

program argAssociation001
use m
    type(Child), allocatable :: c

    allocate(c, SOURCE=Child(2,-2))
    call sub1(null(c))

    contains
    subroutine sub1(arg)
        type(Child), allocatable :: arg
    end subroutine
end

Flang issues an error as

t2.f:16:15: error: A null pointer may not be associated with allocatable dummy argument 'arg=' without INTENT(IN)
      call sub1(null(c))

The code seems conforming to me as I can't find such constraint in the standard. Both XLF and ifort compile the code successfully.

llvmbot commented 2 weeks ago

@llvm/issue-subscribers-flang-frontend

Author: Daniel Chen (DanielCChen)

Consider the following code: ``` module m type Base integer i end type type, extends(Base) :: Child integer j end type end module program argAssociation001 use m type(Child), allocatable :: c allocate(c, SOURCE=Child(2,-2)) call sub1(null(c)) contains subroutine sub1(arg) type(Child), allocatable :: arg end subroutine end ``` Flang issues an error as ``` t2.f:16:15: error: A null pointer may not be associated with allocatable dummy argument 'arg=' without INTENT(IN) call sub1(null(c)) ``` The code seems conforming to me as I can't find such constraint in the standard. Both XLF and ifort compile the code successfully.
llvmbot commented 2 weeks ago

@llvm/issue-subscribers-bug

Author: Daniel Chen (DanielCChen)

Consider the following code: ``` module m type Base integer i end type type, extends(Base) :: Child integer j end type end module program argAssociation001 use m type(Child), allocatable :: c allocate(c, SOURCE=Child(2,-2)) call sub1(null(c)) contains subroutine sub1(arg) type(Child), allocatable :: arg end subroutine end ``` Flang issues an error as ``` t2.f:16:15: error: A null pointer may not be associated with allocatable dummy argument 'arg=' without INTENT(IN) call sub1(null(c)) ``` The code seems conforming to me as I can't find such constraint in the standard. Both XLF and ifort compile the code successfully.
klausler commented 2 weeks ago

That is a valid error. You can pass NULL as an actual argument when the corresponding dummy is a pointer, is optional, or is an INTENT(IN) allocatable. But it doesn't make sense to pass NULL for a dummy that is allocatable and neither optional nor INTENT(IN) -- there's no effective actual argument with which the dummy argument can be associated.

DanielCChen commented 2 weeks ago

@klausler Reopen for some clarification. The standard says the following about the dummy argument.

The actual argument shall be allocatable. It is permissible for the actual argument to have an allocation status of unallocated.

For intrinsic NULL(MOLD).

Result Characteristics. If MOLD is present, the characteristics are the same as MOLD.
...
Result: The result is a disassociated pointer or an unallocated allocatable entity.

This is exactly this test case is testing. The actual argument is an unallocated allocatable object that corresponds to an allocatable dummy.

It initializes the dummy argument using NULL() intrinsic rather than deallocate c first then pass it.

klausler commented 2 weeks ago

But NULL(MOLD=c) is an expression, not a variable, so it is not possible for the actual argument to become defined. That's why I require the INTENT(IN). I should probably relax that to also allow this case of a dummy argument with no INTENT.

DanielCChen commented 1 week ago

@klausler Thanks for the fix. I still think the "warning" message is bit confusing.

NULL(MOLD) is a unique case in the sense that the result is an ... unallocated allocatable entity according to the standard unlike a user defined function that returns an allocatable result. User function allocatable result is the value of it, and it doesn't have the allocatable attribute.

The message requires the dummy argument to have the INTENT(IN) attribute, which it makes the dummy argument useless as users cannot change its allocation status, which is unallocated.

Same for the case of call sub1(NULL()) without the MOLD argument as the standard says it would have the TKR of the corresponding dummy argument.

I think this is a legal case of using intrinsic NULL.

klausler commented 1 week ago

But it is not at all clear that NULL(MOLD=allocatable) produces a definable variable. It doesn't work in XLF as an (unused) input list data item or as a variable in an ALLOCATE or DEALLOCATE statement, and if it appears as the selector of ASSOCIATE, it's not definable.

It is indeed allowed by (only) XLF as the left-hand side of an intrinsic assignment statement and as an actual argument association with an allocatable dummy argument.

So is XLF's behavior something that you believe to be conforming? What are the contexts in which NULL(a) can be used as a definable variable, and what is the lifetime of the anonymous allocatable entity?

DanielCChen commented 1 week ago

Right. I don't think allowing NULL(C) = 4 is intentional as it should fall into the same category as the ALLOCATE and DEALLOCATE statement that require a variable (NULL(C) when c being an allocatable is definitely not a variable).

I now think the wording in the standard that describes the result of NULL(MOLD) being an unallocated allocatable entity is misleading. I also agree now that this should be an error condition that shall have the same treatment as the following code.

interface
  function foo()
    real, allocatable :: foo
  end function
end interface
call sub(foo())
contains
  subroutine sub(arg)
    real, allocatable :: arg
  end
end

Both Flang and XLF issued a similar error message as

6:10: error: ALLOCATABLE dummy argument 'arg=' must be associated with an ALLOCATABLE actual argument
  call sub(foo())
           ^^^^^

I think issuing this error message is probably the better fix for this issue.

klausler commented 1 week ago

No, there's a distinction to be made between NULL(MOLD=allocatable) and a function whose result variable is allocatable. The result of NULL(MOLD=allocatable) is explicitly defined to be an allocatable, whereas the result (in the caller) of the function is explicitly defined to not have the allocatable attribute.

DanielCChen commented 1 week ago

That is exactly where I think the confusion is coming from. The standard is explicit that only the variables and components can have the ALLOCATABLE attribute. If NULL(MOLD=allocatable) is allocatable (have the ALLOCATABLE attribute), then it should be allowed at any places an allocatable variable can appear. However, it doesn't make sense for the cases you listed at the above. For instance, LHS of an intrinsic assignment, ALLOCATE statement. Passing it as an actual argument that corresponds to an allocatable dummy is not as obvious as the other usages, but it should be consistent.

klausler commented 1 week ago

The description of NULL(MOLD=allocatable) explicitly says that its result is an "unallocated allocatable entity". I agree that only named variables and components can have the ALLOCATABLE attribute, but perhaps it is possible for something to be an allocatable without having the attribute.

There must be some justification for NULL(MOLD=allocatable) to have been defined in this way -- there must be some context in which it may appear. The only one that I can come up with is as an actual argument for a dummy allocatable that is not required to be definable.

DanielCChen commented 1 week ago

Ok. I will try to get some answers from the committee.

klausler commented 1 week ago

Good luck with that.