| //@ run-pass |
| |
| #![feature(const_ptr_sub_ptr)] |
| #![feature(ptr_sub_ptr)] |
| |
| 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).sub_ptr(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); |
| } |