[flang-commits] [flang] [flang] Fix RecordType sizes, TRANSFER lowering, and BIND(C) ABI on SystemZ/PPC64le (PR #220377)
via flang-commits
flang-commits at lists.llvm.org
Mon Sep 7 00:43:30 PDT 2026
================
@@ -0,0 +1,67 @@
+! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-hlfir %s -o - | FileCheck %s
+! REQUIRES: x86-registered-target
+
+! Regression test for https://github.com/llvm/llvm-project/pull/220377
+!
+! The TRANSFER inline gate compares store sizes, not allocation sizes.
+! Tail padding must not be included in the comparison.
+!
+! Types declared at module scope so that bare %flang_fc1 does not abort when
+! TRANSFER falls through to the runtime path (pre-existing defect: runtime
+! TRANSFER of a subroutine-local derived type aborts under bare %flang_fc1).
+
+! Shape 1: tail-padded record whose store size matches real(10).
+! t1 fields: integer(8) [8B, align 8] + integer(2) [2B, align 2]
+! Store size = 10B; allocation size = alignTo(10, 8) = 16B.
+! real(10) = f80 on x86-64: store size = 10B.
+! 10 == 10 on store size -> must INLINE (fir.load), not call _FortranATransfer.
+! Without the storeSizeOnly fix the allocation size (16) != 10 and this
+! would wrongly fall through to the runtime path.
+module m1
+ type :: t1
+ integer(8) :: a
+ integer(2) :: b
+ end type
+end module
+
+! Shape 2: tail-padded record whose allocation size matches integer(8) but
+! whose store size does not.
+! t2 fields: integer(4) [4B, align 4] + integer(1) [1B, align 1]
+! Store size = 5B; allocation size = alignTo(5, 4) = 8B.
+! integer(8) store size = 8B.
+! Without the storeSizeOnly fix: 8 == 8 on allocation size -> would inline,
+! but that reads 3 bytes of uninitialized tail padding into the result.
+! With the fix: 5 != 8 on store size -> correctly stays on RUNTIME path.
+module m2
+ type :: t2
+ integer(4) :: a
+ integer(1) :: b
+ end type
+end module
+
+subroutine transfer_rec_to_real10(out)
+ ! CHECK-LABEL: func @_QPtransfer_rec_to_real10(
+ ! CHECK-NOT: fir.call @_FortranATransfer
+ ! CHECK: fir.convert {{.*}} : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<f80>
+ ! CHECK: fir.load {{.*}} : !fir.ref<f80>
----------------
MattPD wrote:
Confirmed that the test now constrains the destination. The source operand remains unconstrained. Copies that use `%[[TMP]]` itself or the output dummy argument as the source pass both the LLVM verifier and FileCheck. The final load can therefore read bytes that did not come from the source record.
Could the test capture the source record allocation and require that value as the second operand of `memcpy`? The source, destination, width, and final load would then form one checked data-flow chain.
https://github.com/llvm/llvm-project/pull/220377
More information about the flang-commits
mailing list