1 #![warn(rust_2018_idioms, single_use_lifetimes)] 2 #![forbid(safe_packed_borrows)] 3 4 use std::cell::Cell; 5 6 // Ensure that the compiler doesn't copy the fields 7 // of #[repr(packed)] types during drop, if the field has alignment 1 8 // (that is, any reference to the field is guaranteed to have proper alignment) 9 // We are currently unable to statically prevent the usage of #[pin_project] 10 // on #[repr(packed)] types composed entirely of fields of alignment 1. 11 // This shouldn't lead to undefined behavior, as long as the compiler doesn't 12 // try to move the field anyway during drop. 13 // 14 // This tests validates that the compiler is doing what we expect. 15 #[test] weird_repr_packed()16fn weird_repr_packed() { 17 // We keep track of the field address during 18 // drop using a thread local, to avoid changing 19 // the layout of our #[repr(packed)] type. 20 thread_local! { 21 static FIELD_ADDR: Cell<usize> = Cell::new(0); 22 } 23 24 #[repr(packed)] 25 struct Struct { 26 field: u8, 27 } 28 29 impl Drop for Struct { 30 fn drop(&mut self) { 31 FIELD_ADDR.with(|f| { 32 f.set(&self.field as *const u8 as usize); 33 }) 34 } 35 } 36 37 #[allow(clippy::let_and_return)] 38 let field_addr = { 39 // We let this field drop by going out of scope, 40 // rather than explicitly calling drop(foo). 41 // Calling drop(foo) causes 'foo' to be moved 42 // into the 'drop' function, resulting in a different 43 // address. 44 let x = Struct { field: 27 }; 45 let field_addr = &x.field as *const u8 as usize; 46 field_addr 47 }; 48 assert_eq!(field_addr, FIELD_ADDR.with(|f| f.get())); 49 } 50