rust/tests/pass/packed_struct.rs
2022-06-01 10:53:38 -04:00

154 lines
3.4 KiB
Rust

#![feature(unsize, coerce_unsized)]
use std::collections::hash_map::DefaultHasher;
use std::hash::Hash;
use std::ptr;
fn test_basic() {
#[repr(packed)]
struct S {
fill: u8,
a: i32,
b: i64,
}
#[repr(packed)]
#[allow(dead_code)]
struct Test1<'a> {
x: u8,
other: &'a u32,
}
#[repr(packed)]
#[allow(dead_code)]
struct Test2<'a> {
x: u8,
other: &'a Test1<'a>,
}
fn test(t: Test2) {
let x = *t.other.other;
assert_eq!(x, 42);
}
let mut x = S {
fill: 0,
a: 42,
b: 99,
};
let a = x.a;
let b = x.b;
assert_eq!(a, 42);
assert_eq!(b, 99);
assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine
// can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference
assert_eq!({x.a}, 42);
assert_eq!({x.b}, 99);
// but we *can* take a raw pointer!
assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42);
assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99);
x.b = 77;
assert_eq!({x.b}, 77);
test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }});
}
fn test_unsizing() {
#[repr(packed)]
#[allow(dead_code)]
struct UnalignedPtr<'a, T: ?Sized>
where T: 'a,
{
data: &'a T,
}
impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
where
T: std::marker::Unsize<U> + ?Sized,
U: ?Sized,
{ }
let arr = [1, 2, 3];
let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors
}
fn test_drop() {
struct Wrap(u32);
impl Drop for Wrap {
fn drop(&mut self) {
// Do an (aligned) load
let _test = self.0;
// For the fun of it, test alignment
assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::<u32>(), 0);
}
}
#[repr(packed,C)]
struct Packed<T> {
f1: u8, // this should move the second field to something not very aligned
f2: T,
}
let p = Packed { f1: 42, f2: Wrap(23) };
drop(p);
}
fn test_inner_packed() {
// Even if just the inner struct is packed, accesses to the outer field can get unaligned.
// Make sure that works.
#[repr(packed)]
#[derive(Clone,Copy)]
struct Inner(u32);
#[derive(Clone,Copy)]
struct Outer(u8, Inner);
let o = Outer(0, Inner(42));
let _x = o.1;
let _y = (o.1).0;
let _o2 = o.clone();
}
fn test_static() {
#[repr(packed)]
struct Foo {
i: i32
}
static FOO: Foo = Foo { i: 42 };
assert_eq!({FOO.i}, 42);
}
fn test_derive() {
#[repr(packed)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
struct P {
a: usize,
b: u8,
c: usize,
}
let x = P {a: 1usize, b: 2u8, c: 3usize};
let y = P {a: 1usize, b: 2u8, c: 4usize};
let _clone = x.clone();
assert!(x != y);
assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y));
x.hash(&mut DefaultHasher::new());
P::default();
format!("{:?}", x);
}
fn main() {
test_basic();
test_unsizing();
test_drop();
test_inner_packed();
test_static();
test_derive();
}