From 73e028006cc22359ccd18e0669ce9da862d198af Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 11 Jul 2026 11:50:58 -0700 Subject: [PATCH 1/3] Add regression test for 159116 --- tests/codegen-llvm/const-array-of-pairs.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/codegen-llvm/const-array-of-pairs.rs diff --git a/tests/codegen-llvm/const-array-of-pairs.rs b/tests/codegen-llvm/const-array-of-pairs.rs new file mode 100644 index 0000000000000..5b93706d48284 --- /dev/null +++ b/tests/codegen-llvm/const-array-of-pairs.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] + +// Regression test for https://github.com/rust-lang/rust/issues/159116 +// where a change had started reading at the wrong offset into a const +// when the sub-object had BackendRepr::ScalarPair + +const PAIRS: [(u64, u64); 3] = [(1, 2), (3, 4), (5, 6)]; + +// CHECK-LABEL: @read_not_first_pair +#[no_mangle] +pub fn read_not_first_pair() -> (u64, u64) { + // FIXME: This is clearly wrong + + // CHECK: start: + // CHECK-NEXT: ret { i64, i64 } { i64 3, i64 2 } + PAIRS[1] +} From 9fddc6909a336947f7929a2cef6aa556f11f3b98 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 11 Jul 2026 11:57:26 -0700 Subject: [PATCH 2/3] Include the subobject offset, not just the field offset, when reading from const --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 7 ++++--- tests/codegen-llvm/const-array-of-pairs.rs | 4 +--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c53dd38a3af5e..22b8272684d36 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -227,10 +227,11 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { BackendRepr::ScalarPair { a: a @ abi::Scalar::Initialized { .. }, b: b @ abi::Scalar::Initialized { .. }, - b_offset, + b_offset: local_b_offset, } => { let (a_size, b_size) = (a.size(bx), b.size(bx)); - assert!(b_offset.bytes() > 0); + let alloc_b_offset = offset + local_b_offset; + assert!(alloc_b_offset.bytes() > 0); let a_val = read_scalar( offset, a_size, @@ -238,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bx.scalar_pair_element_backend_type(layout, 0, true), ); let b_val = read_scalar( - b_offset, + alloc_b_offset, b_size, b, bx.scalar_pair_element_backend_type(layout, 1, true), diff --git a/tests/codegen-llvm/const-array-of-pairs.rs b/tests/codegen-llvm/const-array-of-pairs.rs index 5b93706d48284..438030a2bfa0b 100644 --- a/tests/codegen-llvm/const-array-of-pairs.rs +++ b/tests/codegen-llvm/const-array-of-pairs.rs @@ -11,9 +11,7 @@ const PAIRS: [(u64, u64); 3] = [(1, 2), (3, 4), (5, 6)]; // CHECK-LABEL: @read_not_first_pair #[no_mangle] pub fn read_not_first_pair() -> (u64, u64) { - // FIXME: This is clearly wrong - // CHECK: start: - // CHECK-NEXT: ret { i64, i64 } { i64 3, i64 2 } + // CHECK-NEXT: ret { i64, i64 } { i64 3, i64 4 } PAIRS[1] } From d693dfe22ed55fe5748a98aab1a063854fdcca91 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 11 Jul 2026 12:50:38 -0700 Subject: [PATCH 3/3] Use smaller scalars in the test and force optimizations on Otherwise 32-bit has a different ABI and the `CHECK` fails. And the noopt job fails without forcing MIR optimization here. --- tests/codegen-llvm/const-array-of-pairs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/codegen-llvm/const-array-of-pairs.rs b/tests/codegen-llvm/const-array-of-pairs.rs index 438030a2bfa0b..8c5f71673cc70 100644 --- a/tests/codegen-llvm/const-array-of-pairs.rs +++ b/tests/codegen-llvm/const-array-of-pairs.rs @@ -1,4 +1,4 @@ -//@ compile-flags: -C no-prepopulate-passes +//@ compile-flags: -O -C no-prepopulate-passes #![crate_type = "lib"] @@ -6,12 +6,12 @@ // where a change had started reading at the wrong offset into a const // when the sub-object had BackendRepr::ScalarPair -const PAIRS: [(u64, u64); 3] = [(1, 2), (3, 4), (5, 6)]; +const PAIRS: [(u16, u16); 3] = [(1, 2), (3, 4), (5, 6)]; // CHECK-LABEL: @read_not_first_pair #[no_mangle] -pub fn read_not_first_pair() -> (u64, u64) { +pub fn read_not_first_pair() -> (u16, u16) { // CHECK: start: - // CHECK-NEXT: ret { i64, i64 } { i64 3, i64 4 } + // CHECK-NEXT: ret { i16, i16 } { i16 3, i16 4 } PAIRS[1] }