From e67e7162f700b29462294c3c45f686462706b7e5 Mon Sep 17 00:00:00 2001 From: dianqk Date: Thu, 16 Apr 2026 21:21:58 +0800 Subject: [PATCH] Add miscompiled test cases --- .../indirect-bycopy-bymove-byval.rs | 102 ++++++++++++++++++ .../ui/moves/bycopy_untupled.noopt.run.stderr | 6 ++ tests/ui/moves/bycopy_untupled.opt.run.stderr | 1 + tests/ui/moves/bycopy_untupled.rs | 58 ++++++++++ 4 files changed, 167 insertions(+) create mode 100644 tests/codegen-llvm/indirect-bycopy-bymove-byval.rs create mode 100644 tests/ui/moves/bycopy_untupled.noopt.run.stderr create mode 100644 tests/ui/moves/bycopy_untupled.opt.run.stderr create mode 100644 tests/ui/moves/bycopy_untupled.rs diff --git a/tests/codegen-llvm/indirect-bycopy-bymove-byval.rs b/tests/codegen-llvm/indirect-bycopy-bymove-byval.rs new file mode 100644 index 000000000000..7908fa468287 --- /dev/null +++ b/tests/codegen-llvm/indirect-bycopy-bymove-byval.rs @@ -0,0 +1,102 @@ +//! Regression test for issue . +//! Arguments passed indirectly via a hidden pointer must be copied to an alloca, +//! except for by-val or by-move. +//@ add-minicore +//@ revisions: x64-linux i686-linux i686-windows +//@ compile-flags: -Cno-prepopulate-passes -Copt-level=3 +//@[x64-linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[x64-linux] needs-llvm-components: x86 +//@[i686-linux] compile-flags: --target i686-unknown-linux-gnu +//@[i686-linux] needs-llvm-components: x86 +//@[i686-windows] compile-flags: --target i686-pc-windows-msvc +//@[i686-windows] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(stmt_expr_attributes, no_core)] +#![expect(unused)] +#![no_std] +#![no_core] + +extern crate minicore; +use minicore::*; + +struct Thing(u64, u64, u64); + +impl Copy for Thing {} + +// The argument of the second call is a by-move argument. + +// CHECK-LABEL: @normal +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[normal_V1:%.*]], ptr{{.*}} %value, +// CHECK: call void @opaque(ptr{{.*}} [[normal_V1]]) +// CHECK: call void @opaque(ptr{{.*}} %value) +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[normal_V3:%.*]], ptr{{.*}} @anon{{.*}}, +// CHECK: call void @opaque(ptr{{.*}} [[normal_V3]]) +#[unsafe(no_mangle)] +pub fn normal() { + #[inline(never)] + #[unsafe(no_mangle)] + fn opaque(mut thing: Thing) { + thing.0 = 1; + } + let value = Thing(0, 0, 0); + opaque(value); + opaque(value); + const VALUE: Thing = Thing(0, 0, 0); + opaque(VALUE); +} + +// FIXME: closure#0 and closure#1 are missing memcpy. + +// CHECK-LABEL: @untupled +// CHECK: call indirect_bycopy_bymove_byval::untupled::{closure#0} +// CHECK-NEXT: call void @{{.*}}(ptr {{.*}}, ptr{{.*}} %value) +// CHECK: call indirect_bycopy_bymove_byval::untupled::{closure#1} +// CHECK-NEXT: call void @{{.*}}(ptr {{.*}}, ptr{{.*}} %value) +// CHECK: call indirect_bycopy_bymove_byval::untupled::{closure#2} +// CHECK-NEXT: call void @{{.*}}(ptr {{.*}}, ptr{{.*}} @anon{{.*}}) +#[unsafe(no_mangle)] +pub fn untupled() { + let value = (Thing(0, 0, 0),); + (#[inline(never)] + |mut thing: Thing| { + thing.0 = 1; + }) + .call(value); + (#[inline(never)] + |mut thing: Thing| { + thing.0 = 2; + }) + .call(value); + const VALUE: (Thing,) = (Thing(0, 0, 0),); + (#[inline(never)] + |mut thing: Thing| { + thing.0 = 3; + }) + .call(VALUE); +} + +// FIXME: all memcpy calls are redundant for byval. + +// CHECK-LABEL: @byval +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[byval_V1:%.*]], ptr{{.*}} %value, +// CHECK: call void @opaque_byval(ptr{{.*}} byval([24 x i8]){{.*}} [[byval_V1]]) +// CHECK: call void @opaque_byval(ptr{{.*}} byval([24 x i8]){{.*}} %value) +// CHECK: call void @llvm.memcpy{{.*}}(ptr{{.*}} [[byval_V3:%.*]], ptr{{.*}} @anon{{.*}}, +// CHECK: call void @opaque_byval(ptr{{.*}} byval([24 x i8]){{.*}} [[byval_V3]]) +#[unsafe(no_mangle)] +pub fn byval() { + #[repr(C)] + struct Thing(u64, u64, u64); + impl Copy for Thing {} + #[inline(never)] + #[unsafe(no_mangle)] + extern "C" fn opaque_byval(mut thing: Thing) { + thing.0 = 1; + } + let value = Thing(0, 0, 0); + opaque_byval(value); + opaque_byval(value); + const VALUE: Thing = Thing(0, 0, 0); + opaque_byval(VALUE); +} diff --git a/tests/ui/moves/bycopy_untupled.noopt.run.stderr b/tests/ui/moves/bycopy_untupled.noopt.run.stderr new file mode 100644 index 000000000000..9eaded6c0165 --- /dev/null +++ b/tests/ui/moves/bycopy_untupled.noopt.run.stderr @@ -0,0 +1,6 @@ + +thread 'main' ($TID) panicked at $DIR/bycopy_untupled.rs:25:5: +assertion `left == right` failed + left: 1 + right: 0 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/moves/bycopy_untupled.opt.run.stderr b/tests/ui/moves/bycopy_untupled.opt.run.stderr new file mode 100644 index 000000000000..915e3ecb5436 --- /dev/null +++ b/tests/ui/moves/bycopy_untupled.opt.run.stderr @@ -0,0 +1 @@ +free(): double free detected in tcache 2 diff --git a/tests/ui/moves/bycopy_untupled.rs b/tests/ui/moves/bycopy_untupled.rs new file mode 100644 index 000000000000..9eca69e50379 --- /dev/null +++ b/tests/ui/moves/bycopy_untupled.rs @@ -0,0 +1,58 @@ +//@[noopt] run-fail +//@[opt] run-crash +//@ revisions: noopt opt +//@ check-run-results +//@[noopt] compile-flags: -C opt-level=0 +//@[opt] compile-flags: -C opt-level=3 + +#![feature(fn_traits, stmt_expr_attributes)] +#![expect(unused)] + +#[derive(Copy, Clone)] +struct Thing { + x: usize, + y: usize, + z: usize, +} + +#[inline(never)] +fn opt_0() { + let value = (Thing { x: 0, y: 0, z: 0 },); + (|mut thing: Thing| { + thing.z = 1; + }) + .call(value); + assert_eq!(value.0.z, 0); +} + +#[inline(never)] +fn opt_3() { + fn with(f: impl FnOnce(Vec)) { + f(Vec::new()) + } + with(|mut v| v.resize(2, 1)); + with(|v| { + if v.len() != 0 { + unreachable!(); + } + }); +} + +#[inline(never)] +fn const_() { + const VALUE: (Thing,) = (Thing { x: 0, y: 0, z: 0 },); + + (#[inline(never)] + |mut thing: Thing| { + thing.z = 1; + std::hint::black_box(&mut thing.z); + assert_eq!(thing.z, 1); + }) + .call(VALUE); +} + +fn main() { + opt_0(); + opt_3(); + const_(); +}