[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