When a MIR argument is spread at ABI level, deduced attributes are potentially misapplied, since a spread argument can correspond to zero or more arguments at ABI level. Disable deduction for MIR using spread argument for the time being.
181 lines
4.8 KiB
Rust
181 lines
4.8 KiB
Rust
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
|
|
//@ compile-flags: -Cpanic=abort -Csymbol-mangling-version=v0
|
|
//@ revisions: LLVM21 LLVM20
|
|
//@ [LLVM21] min-llvm-version: 21
|
|
//@ [LLVM20] max-llvm-major-version: 20
|
|
#![feature(custom_mir, core_intrinsics, unboxed_closures)]
|
|
#![crate_type = "lib"]
|
|
extern crate core;
|
|
use core::intrinsics::mir::*;
|
|
use std::cell::Cell;
|
|
use std::hint::black_box;
|
|
use std::mem::ManuallyDrop;
|
|
|
|
pub struct Big {
|
|
pub blah: [i32; 1024],
|
|
}
|
|
|
|
pub struct BigCell {
|
|
pub blah: [Cell<i32>; 1024],
|
|
}
|
|
|
|
pub struct BigDrop {
|
|
pub blah: [u8; 1024],
|
|
}
|
|
|
|
impl Drop for BigDrop {
|
|
#[inline(never)]
|
|
fn drop(&mut self) {}
|
|
}
|
|
|
|
// CHECK-LABEL: @mutate(
|
|
// CHECK-NOT: readonly
|
|
// CHECK-SAME: %b)
|
|
#[unsafe(no_mangle)]
|
|
pub fn mutate(mut b: Big) {
|
|
b.blah[987] = 654;
|
|
black_box(&b);
|
|
}
|
|
|
|
// LLVM21-LABEL: @deref_mut({{.*}}readonly {{.*}}captures(none) {{.*}}%c)
|
|
// LLVM20-LABEL: @deref_mut({{.*}}readonly {{.*}}%c)
|
|
#[unsafe(no_mangle)]
|
|
pub fn deref_mut(c: (BigCell, &mut usize)) {
|
|
*c.1 = 42;
|
|
}
|
|
|
|
// LLVM21-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}}captures(none){{.*}})
|
|
// LLVM20-LABEL: @call_copy_arg(ptr {{.*}}readonly {{.*}})
|
|
#[unsafe(no_mangle)]
|
|
#[custom_mir(dialect = "runtime", phase = "optimized")]
|
|
pub fn call_copy_arg(a: Big) {
|
|
mir! {
|
|
{
|
|
Call(RET = call_copy_arg(a), ReturnTo(bb1), UnwindUnreachable())
|
|
}
|
|
bb1 = {
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: @call_move_arg(
|
|
// CHECK-NOT: readonly
|
|
// LLVM21-SAME: captures(address)
|
|
// CHECK-SAME: )
|
|
#[unsafe(no_mangle)]
|
|
#[custom_mir(dialect = "runtime", phase = "optimized")]
|
|
pub fn call_move_arg(a: Big) {
|
|
mir! {
|
|
{
|
|
Call(RET = call_move_arg(Move(a)), ReturnTo(bb1), UnwindUnreachable())
|
|
}
|
|
bb1 = {
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn shared_borrow<T>(a: T) {
|
|
black_box(&a);
|
|
}
|
|
|
|
// Freeze parameter cannot be mutated through a shared borrow.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::<deduced_param_attrs::Big>
|
|
// CHECK-NEXT: ;
|
|
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(address) {{.*}}%a)
|
|
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}}%a)
|
|
pub static A0: fn(Big) = shared_borrow;
|
|
|
|
// !Freeze parameter can be mutated through a shared borrow.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::shared_borrow::<deduced_param_attrs::BigCell>
|
|
// CHECK-NEXT: ;
|
|
// CHECK-NOT: readonly
|
|
// CHECK-NEXT: %a)
|
|
pub static A1: fn(BigCell) = shared_borrow;
|
|
|
|
// The parameter can be mutated through a raw const borrow.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::raw_const_borrow
|
|
// CHECK-NOT: readonly
|
|
// CHECK-NEXT : %a)
|
|
#[inline(never)]
|
|
pub fn raw_const_borrow(a: Big) {
|
|
black_box(&raw const a);
|
|
}
|
|
|
|
fn consume<T>(_: T) {}
|
|
|
|
// The parameter doesn't need to be dropped.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigCell>
|
|
// CHECK-NEXT: ;
|
|
// LLVM21-NEXT: (ptr {{.*}}readonly {{.*}}captures(none) {{.*}})
|
|
// LLVM20-NEXT: (ptr {{.*}}readonly {{.*}})
|
|
pub static B0: fn(BigCell) = consume;
|
|
|
|
// The parameter needs to be dropped.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::consume::<deduced_param_attrs::BigDrop>
|
|
// CHECK-NEXT: ;
|
|
// LLVM21-NEXT: (ptr {{.*}}captures(address) {{.*}})
|
|
// LLVM20-NEXT: (ptr {{.*}})
|
|
pub static B1: fn(BigDrop) = consume;
|
|
|
|
fn consume_parts<T>(t: (T, T)) {
|
|
let (_t0, ..) = t;
|
|
}
|
|
|
|
// In principle it would be possible to deduce readonly here.
|
|
//
|
|
// CHECK-LABEL: ; deduced_param_attrs::consume_parts::<[u8; 40]>
|
|
// CHECK-NEXT: ;
|
|
// CHECK-NOT: readonly
|
|
// CHECK-NEXT: %t)
|
|
pub static C1: fn(([u8; 40], [u8; 40])) = consume_parts;
|
|
|
|
// The inner field of ManuallyDrop<BigDrop> needs to be dropped.
|
|
//
|
|
// CHECK-LABEL: @manually_drop_field(
|
|
// CHECK-NOT: readonly
|
|
// CHECK-SAME: %b)
|
|
#[unsafe(no_mangle)]
|
|
pub fn manually_drop_field(a: fn() -> BigDrop, mut b: ManuallyDrop<BigDrop>) {
|
|
// FIXME(tmiasko) replace with custom MIR, instead of expecting MIR optimizations to turn this
|
|
// into: drop((_2.0: BigDrop))
|
|
*b = a();
|
|
unsafe { core::intrinsics::unreachable() }
|
|
}
|
|
|
|
// `readonly` is omitted from the return place, even when applicable.
|
|
//
|
|
// CHECK-LABEL: @never_returns(
|
|
// CHECK-NOT: readonly
|
|
// CHECK-SAME: %_0)
|
|
#[unsafe(no_mangle)]
|
|
pub fn never_returns() -> [u8; 80] {
|
|
loop {}
|
|
}
|
|
|
|
// LLVM21-LABEL: @not_captured_return_place(ptr{{.*}} captures(none) {{.*}}%_0)
|
|
#[unsafe(no_mangle)]
|
|
pub fn not_captured_return_place() -> [u8; 80] {
|
|
[0u8; 80]
|
|
}
|
|
|
|
// LLVM21-LABEL: @captured_return_place(ptr{{.*}} captures(address) {{.*}}%_0)
|
|
#[unsafe(no_mangle)]
|
|
pub fn captured_return_place() -> [u8; 80] {
|
|
black_box([0u8; 80])
|
|
}
|
|
|
|
// Arguments spread at ABI level are unsupported.
|
|
//
|
|
// CHECK-LABEL: @spread_arg(
|
|
// CHECK-NOT: readonly
|
|
// CHECK-SAME: )
|
|
#[no_mangle]
|
|
pub extern "rust-call" fn spread_arg(_: (Big, Big, Big)) {}
|