rust/tests/ui/lint/unaligned_references.rs
2024-08-08 11:58:11 -04:00

143 lines
3.9 KiB
Rust

//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
use std::fmt::Debug;
use std::mem::ManuallyDrop;
#[repr(packed)]
pub struct Good {
data: u64,
ptr: &'static u64,
data2: [u64; 2],
aligned: [u8; 32],
}
#[repr(packed(2))]
pub struct Packed2 {
x: u32,
y: u16,
z: u8,
}
trait Foo {
fn evil(&self);
}
// Test for #108122
#[automatically_derived]
impl Foo for Packed2 {
fn evil(&self) {
unsafe {
&self.x; //~ ERROR reference to packed field
}
}
}
// Test for #115396
fn packed_dyn() {
#[repr(packed)]
struct Unaligned<T: ?Sized>(ManuallyDrop<T>);
let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64]));
let foo: &Unaligned<dyn Debug> = &*local;
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
let foo: &Unaligned<[u64]> = &*local;
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
// Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8]));
let foo: &Unaligned<dyn Debug> = &*local;
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
// However, we *can* know the alignment when looking at a slice.
let foo: &Unaligned<[u8]> = &*local;
println!("{:?}", &*foo.0); // no error!
}
// Test for #115396
fn packed_slice_behind_alias() {
trait Mirror {
type Assoc: ?Sized;
}
impl<T: ?Sized> Mirror for T {
type Assoc = T;
}
struct W<T: ?Sized>(<T as Mirror>::Assoc);
#[repr(packed)]
struct Unaligned<T: ?Sized>(ManuallyDrop<W<T>>);
// Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
let ref local: Unaligned<[_; 3]> = Unaligned(ManuallyDrop::new(W([3, 5, 8u8])));
let foo: &Unaligned<[u8]> = local;
let x = &foo.0; // Fine, since the tail of `foo` is `[_]`
}
fn main() {
unsafe {
let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
let _ = &good.ptr; //~ ERROR reference to packed field
let _ = &good.data; //~ ERROR reference to packed field
// Error even when turned into raw pointer immediately.
let _ = &good.data as *const _; //~ ERROR reference to packed field
let _: *const _ = &good.data; //~ ERROR reference to packed field
// Error on method call.
let _ = good.data.clone(); //~ ERROR reference to packed field
// Error for nested fields.
let _ = &good.data2[0]; //~ ERROR reference to packed field
let _ = &*good.ptr; // ok, behind a pointer
let _ = &good.aligned; // ok, has align 1
let _ = &good.aligned[2]; // ok, has align 1
}
unsafe {
let packed2 = Packed2 { x: 0, y: 0, z: 0 };
let _ = &packed2.x; //~ ERROR reference to packed field
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
let _ = &packed2.z; // ok, has align 1
packed2.evil();
}
unsafe {
struct U16(u16);
impl Drop for U16 {
fn drop(&mut self) {
println!("{:p}", self);
}
}
struct HasDrop;
impl Drop for HasDrop {
fn drop(&mut self) {}
}
#[allow(unused)]
struct Wrapper {
a: U16,
b: HasDrop,
}
#[allow(unused)]
#[repr(packed(2))]
struct Wrapper2 {
a: U16,
b: HasDrop,
}
// An outer struct with more restrictive packing than the inner struct -- make sure we
// notice that!
#[repr(packed)]
struct Misalign<T>(u8, T);
let m1 = Misalign(0, Wrapper { a: U16(10), b: HasDrop });
let _ref = &m1.1.a; //~ ERROR reference to packed field
let m2 = Misalign(0, Wrapper2 { a: U16(10), b: HasDrop });
let _ref = &m2.1.a; //~ ERROR reference to packed field
}
}