[flang-commits] [flang] [flang] Propagate INTENT(IN) dummy arguments as readonly (PR #207732)

Sergey Shcherbinin via flang-commits flang-commits at lists.llvm.org
Sat Jul 11 10:28:09 PDT 2026


================
@@ -187,6 +187,30 @@ asImplicitArg(Fortran::evaluate::characteristics::DummyDataObject &&dummy) {
                                                        std::move(shape)));
 }
 
+/// An INTENT(IN) data object passed by reference is not modified by the callee,
+/// so the LLVM `readonly` argument attribute can be set. Notes on the
+/// exclusions:
+///   - VALUE, POINTER, and ALLOCATABLE dummies require ABI- or
+///     descriptor-specific handling before `readonly` can be applied and are
+///     left out of scope;
+///   - ASYNCHRONOUS memory may change underneath the callee;
+///   - VOLATILE+INTENT(IN) is prohibited by the standard (C870); kept here
+///     defensively.
+/// TARGET and derived types are intentionally allowed: any write that
+/// INTENT(IN) still permits (e.g. writing the target of a POINTER component)
+/// goes through a pointer loaded from the object, not through the argument
+/// pointer, and hence does not violate LLVM `readonly` (which only constrains
+/// the argument and pointers based on it).
+static bool dummyArgIsReadOnly(
----------------
SergeyShch01 wrote:

Thanks for raising the forwarding case as well. I believe the complete example is nonconforming, although the call inner(x) statement itself is not prohibited by a constraint:
```
subroutine inner(y)
  integer :: y
  y = 99
end subroutine
subroutine outer(x)
  integer, intent(in) :: x
  call inner(x)
end subroutine
```
C846 does not reject the call. Under F2023 19.6.7, an actual argument is a variable-definition context when an explicit interface declares the corresponding nonpointer dummy as INTENT(OUT) or INTENT(INOUT). Here y has no INTENT, so the call is not a variable-definition context and C846 does not apply. In this presentation, inner also has an implicit interface at the call site, which makes a compile-time diagnostic even less available; however, even with an explicit interface declaring y without INTENT, C846 would still not reject the call. [F2023 C846 and 19.6.7](https://j3-fortran.org/doc/year/23/23-007r1.pdf#page=566)
However, F2023 8.5.10 explicitly specifies what happens when the callee dummy has no INTENT: its use
	“is subject to the limitations of its effective argument”.
The effective argument of y is x, so uses of y are subject to the INTENT(IN) restriction on x. Paragraph 2 states that such a dummy
	“shall neither be defined nor become undefined during the invocation and execution”.
Consequently, y = 99 defines storage associated with x while outer is executing and violates 8.5.10p2. [F2023 8.5.10p2 and p5](https://j3-fortran.org/doc/year/23/23-007r1.pdf#page=127)
Note 4 is consistent with this: an effective argument corresponding to a dummy without INTENT needs to permit definition only if that dummy is actually redefined. Here it is actually redefined, while INTENT(IN) prohibits that definition.
Malcolm Cohen, editor of the Fortran standard, uses the same model in [J3/25-179r1](https://j3-fortran.org/doc/year/25/25-179r1.txt). For forwarding a protected object to a dummy with unspecified INTENT, the example says that the call is:
	“Valid if and only if Q is not assigned to”.
Although J3/25-179r1 is a requirements paper for readonly pointers rather than an official interpretation, it clearly confirms the distinction: forwarding is allowed, but an actual write through the receiving dummy is not.
Therefore:
	• If inner only reads y, call inner(x) is conforming.
	• If inner defines y, as in this example, the program is nonconforming.
	• No diagnostic is required because the violation is not exposed by C846 and can depend on an unavailable callee body.
I think the forwarding statement in Flang’s Aliasing.md should therefore be understood as a conservative analysis warning: forwarding to an unspecified-INTENT dummy makes a possible write difficult to diagnose statically, but it does not make that write conforming under 8.5.10.
This is compatible with LLVM readonly: the attribute forbids writes through the argument pointer and pointers derived from it. In a conforming program, a callee receiving a forwarded x must not write through that pointer, so readonly on outer’s x remains valid. [LLVM Language Reference](https://llvm.org/docs/LangRef.html#parameter-attributes)
Thus, the forwarding case does not require excluding INTENT(IN) arguments from the proposed readonly propagation.

https://github.com/llvm/llvm-project/pull/207732


More information about the flang-commits mailing list