[flang-commits] [flang] 06a7d41 - [flang] Disable copy-out to INTENT(IN) args (#192382)
via flang-commits
flang-commits at lists.llvm.org
Wed Apr 22 19:11:42 PDT 2026
Author: Eugene Epshteyn
Date: 2026-04-22T22:11:37-04:00
New Revision: 06a7d41eb12bd5c9b4f3fae94f31f644d1816688
URL: https://github.com/llvm/llvm-project/commit/06a7d41eb12bd5c9b4f3fae94f31f644d1816688
DIFF: https://github.com/llvm/llvm-project/commit/06a7d41eb12bd5c9b4f3fae94f31f644d1816688.diff
LOG: [flang] Disable copy-out to INTENT(IN) args (#192382)
Don't copy out to actual args that themselves happen to be INTENT(IN)
dummy args.
```
subroutine test(a)
real, intent(in) :: a(:)
call require_contiguous_arg(a(1:n:2)) ! copy-in only, no copy-out
end
```
---------
Co-authored-by: Claude Sonnet 4.6 <noreply at anthropic.com>
Added:
Modified:
flang/lib/Evaluate/check-expression.cpp
flang/test/Lower/call-copy-in-out.f90
Removed:
################################################################################
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index be7db0f20821d..62c93e5d20737 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -1649,6 +1649,21 @@ std::optional<bool> ActualArgNeedsCopy(const ActualArgument *actual,
// Expressions are copy-in, but not copy-out.
return forCopyIn;
}
+ if (forCopyOut) {
+ // F2023 8.5.10 C846/p2/p6: a nonpointer INTENT(IN) dummy and its
+ // subobjects may not be defined. Suppress copy-out when the actual
+ // argument is a subobject of a nonpointer INTENT(IN) dummy.
+ // Exception: a data-ref that goes through a pointer component defines the
+ // pointer's target, which is not a subobject of the dummy (F2023 9.4.2
+ // p5), so copy-out is still needed in that case.
+ if (const auto dataRef{ExtractDataRef(*actual)}) {
+ const Symbol &firstSym{dataRef->GetFirstSymbol()};
+ if (semantics::IsIntentIn(firstSym) && !IsPointer(firstSym) &&
+ !GetLastPointerSymbol(*dataRef)) {
+ return false;
+ }
+ }
+ }
auto maybeContigActual{IsContiguous(*actual, fc)};
if (dummyObj) { // Explict interface
CopyInOutExplicitInterface check{fc, *actual, *dummyObj};
diff --git a/flang/test/Lower/call-copy-in-out.f90 b/flang/test/Lower/call-copy-in-out.f90
index fa2182ac11bac..5d754d8a9ac28 100644
--- a/flang/test/Lower/call-copy-in-out.f90
+++ b/flang/test/Lower/call-copy-in-out.f90
@@ -84,6 +84,50 @@ subroutine bar_intent_in(x)
call bar_intent_in(x)
end subroutine
+! Test copy-out is skipped when the actual argument has INTENT(IN).
+! A copy-in is still needed for the contiguous-requiring callee, but
+! the temp is only deallocated on return, not copied back (no "to" clause).
+! CHECK-LABEL: func @_QPtest_actual_arg_intent_in(
+subroutine test_actual_arg_intent_in(x)
+ real, intent(in) :: x(:)
+! CHECK: hlfir.copy_in
+! CHECK: fir.call @_QPbar
+! CHECK: hlfir.copy_out
+! CHECK-NOT: to
+! CHECK: return
+ call bar(x)
+end subroutine
+
+! Test copy-out is NOT skipped when passing a section of a pointer component
+! of an INTENT(IN) dummy: the pointer target is not a subobject of the dummy
+! (F2023 9.4.2 p5), so the callee may define it and copy-out is required.
+! CHECK-LABEL: func @_QPtest_actual_arg_intent_in_ptr_component(
+subroutine test_actual_arg_intent_in_ptr_component(x)
+ type :: t
+ integer, pointer :: p(:)
+ end type
+ type(t), intent(in) :: x
+! CHECK: hlfir.copy_in
+! CHECK: fir.call @_QPbar_integer
+! CHECK: hlfir.copy_out
+! CHECK-SAME: to
+ call bar_integer(x%p(1:4:2))
+end subroutine
+
+! Test copy-out is NOT skipped when the actual is a section of an INTENT(IN)
+! pointer dummy: INTENT(IN) on a pointer restricts pointer association, not
+! the target's contents, so the callee may define the target and copy-out is
+! required.
+! CHECK-LABEL: func @_QPtest_actual_intent_in_pointer(
+subroutine test_actual_intent_in_pointer(pi)
+ integer, intent(in), pointer :: pi(:)
+! CHECK: hlfir.copy_in
+! CHECK: fir.call @_QPbar_integer
+! CHECK: hlfir.copy_out
+! CHECK-SAME: to
+ call bar_integer(pi(1:4:2))
+end subroutine
+
! Test copy-in/copy-out is done for intent(inout)
! CHECK-LABEL: func @_QPtest_intent_inout(
subroutine test_intent_inout(x)
More information about the flang-commits
mailing list