Add miscompiled test cases

This commit is contained in:
dianqk
2026-04-16 21:21:58 +08:00
parent e8e4541ff1
commit e67e7162f7
4 changed files with 167 additions and 0 deletions
@@ -0,0 +1,102 @@
//! Regression test for issue <https://github.com/rust-lang/rust/issues/155241>.
//! 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);
}
@@ -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
@@ -0,0 +1 @@
free(): double free detected in tcache 2
+58
View File
@@ -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<usize>)) {
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_();
}