| //@ run-pass | |
| struct Struct { | |
| field: (), | |
| } | |
| #[repr(C)] | |
| struct Struct2 { | |
| data: u8, | |
| field: u8, | |
| } | |
| pub const OFFSET: usize = { | |
| let uninit = std::mem::MaybeUninit::<Struct>::uninit(); | |
| let base_ptr: *const Struct = &uninit as *const _ as *const Struct; | |
| // The following statement is UB (taking the address of an uninitialized field). | |
| // Const eval doesn't detect this right now, but it may stop compiling at some point | |
| // in the future. | |
| let field_ptr = unsafe { &(*base_ptr).field as *const () as *const u8 }; | |
| let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; | |
| offset as usize | |
| }; | |
| pub const OFFSET_2: usize = { | |
| let uninit = std::mem::MaybeUninit::<Struct2>::uninit(); | |
| let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; | |
| let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; | |
| let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) }; | |
| offset as usize | |
| }; | |
| pub const OVERFLOW: isize = { | |
| let uninit = std::mem::MaybeUninit::<Struct2>::uninit(); | |
| let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2; | |
| let field_ptr = unsafe { &(*base_ptr).field as *const u8 }; | |
| unsafe { (base_ptr as *const u8).offset_from(field_ptr) } | |
| }; | |
| pub const OFFSET_EQUAL_INTS: isize = { | |
| let ptr = 1 as *const u8; | |
| unsafe { ptr.offset_from(ptr) } | |
| }; | |
| pub const OFFSET_UNSIGNED: usize = { | |
| let a = ['a', 'b', 'c']; | |
| let ptr = a.as_ptr(); | |
| unsafe { ptr.add(2).offset_from_unsigned(ptr) } | |
| }; | |
| fn main() { | |
| assert_eq!(OFFSET, 0); | |
| assert_eq!(OFFSET_2, 1); | |
| assert_eq!(OVERFLOW, -1); | |
| assert_eq!(OFFSET_EQUAL_INTS, 0); | |
| assert_eq!(OFFSET_UNSIGNED, 2); | |
| } |