2016-12-12 02:51:22 +00:00
|
|
|
|
use core::cell::RefCell;
|
2021-01-18 19:45:34 +00:00
|
|
|
|
use core::ptr;
|
|
|
|
|
use core::ptr::*;
|
2020-12-29 17:31:22 +00:00
|
|
|
|
use std::fmt::{Debug, Display};
|
2014-06-28 20:57:36 +00:00
|
|
|
|
|
2019-12-20 20:42:03 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_const_from_raw_parts() {
|
|
|
|
|
const SLICE: &[u8] = &[1, 2, 3, 4];
|
|
|
|
|
const FROM_RAW: &[u8] = unsafe { &*slice_from_raw_parts(SLICE.as_ptr(), SLICE.len()) };
|
|
|
|
|
assert_eq!(SLICE, FROM_RAW);
|
|
|
|
|
|
|
|
|
|
let slice = &[1, 2, 3, 4, 5];
|
2019-12-22 22:42:04 +00:00
|
|
|
|
let from_raw = unsafe { &*slice_from_raw_parts(slice.as_ptr(), 2) };
|
2019-12-20 20:42:03 +00:00
|
|
|
|
assert_eq!(&slice[..2], from_raw);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-28 20:57:36 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test() {
|
|
|
|
|
unsafe {
|
|
|
|
|
struct Pair {
|
2015-03-26 00:06:52 +00:00
|
|
|
|
fst: isize,
|
2019-12-07 04:18:12 +00:00
|
|
|
|
snd: isize,
|
2020-11-25 22:00:28 +00:00
|
|
|
|
}
|
2019-12-07 04:18:12 +00:00
|
|
|
|
let mut p = Pair { fst: 10, snd: 20 };
|
2014-06-28 20:57:36 +00:00
|
|
|
|
let pptr: *mut Pair = &mut p;
|
2015-07-24 01:04:55 +00:00
|
|
|
|
let iptr: *mut isize = pptr as *mut isize;
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert_eq!(*iptr, 10);
|
|
|
|
|
*iptr = 30;
|
|
|
|
|
assert_eq!(*iptr, 30);
|
|
|
|
|
assert_eq!(p.fst, 30);
|
|
|
|
|
|
2019-12-07 04:18:12 +00:00
|
|
|
|
*pptr = Pair { fst: 50, snd: 60 };
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert_eq!(*iptr, 50);
|
|
|
|
|
assert_eq!(p.fst, 50);
|
|
|
|
|
assert_eq!(p.snd, 60);
|
|
|
|
|
|
|
|
|
|
let v0 = vec![32000u16, 32001u16, 32002u16];
|
|
|
|
|
let mut v1 = vec![0u16, 0u16, 0u16];
|
|
|
|
|
|
2015-03-27 18:12:28 +00:00
|
|
|
|
copy(v0.as_ptr().offset(1), v1.as_mut_ptr().offset(1), 1);
|
2019-12-07 04:18:12 +00:00
|
|
|
|
assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
|
2015-03-27 18:12:28 +00:00
|
|
|
|
copy(v0.as_ptr().offset(2), v1.as_mut_ptr(), 1);
|
2019-12-07 04:18:12 +00:00
|
|
|
|
assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 0u16));
|
2015-03-27 18:12:28 +00:00
|
|
|
|
copy(v0.as_ptr(), v1.as_mut_ptr().offset(2), 1);
|
2019-12-07 04:18:12 +00:00
|
|
|
|
assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && v1[2] == 32000u16));
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_is_null() {
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p: *const isize = null();
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert!(p.is_null());
|
|
|
|
|
|
2019-02-17 11:58:48 +00:00
|
|
|
|
let q = p.wrapping_offset(1);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert!(!q.is_null());
|
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let mp: *mut isize = null_mut();
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert!(mp.is_null());
|
|
|
|
|
|
2019-02-17 11:58:48 +00:00
|
|
|
|
let mq = mp.wrapping_offset(1);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
assert!(!mq.is_null());
|
2017-10-10 18:35:41 +00:00
|
|
|
|
|
|
|
|
|
// Pointers to unsized types -- slices
|
|
|
|
|
let s: &mut [u8] = &mut [1, 2, 3];
|
|
|
|
|
let cs: *const [u8] = s;
|
|
|
|
|
assert!(!cs.is_null());
|
|
|
|
|
|
|
|
|
|
let ms: *mut [u8] = s;
|
|
|
|
|
assert!(!ms.is_null());
|
|
|
|
|
|
|
|
|
|
let cz: *const [u8] = &[];
|
|
|
|
|
assert!(!cz.is_null());
|
|
|
|
|
|
|
|
|
|
let mz: *mut [u8] = &mut [];
|
|
|
|
|
assert!(!mz.is_null());
|
|
|
|
|
|
|
|
|
|
let ncs: *const [u8] = null::<[u8; 3]>();
|
|
|
|
|
assert!(ncs.is_null());
|
|
|
|
|
|
|
|
|
|
let nms: *mut [u8] = null_mut::<[u8; 3]>();
|
|
|
|
|
assert!(nms.is_null());
|
|
|
|
|
|
|
|
|
|
// Pointers to unsized types -- trait objects
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let ci: *const dyn ToString = &3;
|
2017-10-10 18:35:41 +00:00
|
|
|
|
assert!(!ci.is_null());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let mi: *mut dyn ToString = &mut 3;
|
2017-10-10 18:35:41 +00:00
|
|
|
|
assert!(!mi.is_null());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let nci: *const dyn ToString = null::<isize>();
|
2017-10-10 18:35:41 +00:00
|
|
|
|
assert!(nci.is_null());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let nmi: *mut dyn ToString = null_mut::<isize>();
|
2017-10-10 18:35:41 +00:00
|
|
|
|
assert!(nmi.is_null());
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2014-08-20 20:06:34 +00:00
|
|
|
|
fn test_as_ref() {
|
2014-06-28 20:57:36 +00:00
|
|
|
|
unsafe {
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p: *const isize = null();
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert_eq!(p.as_ref(), None);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let q: *const isize = &2;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert_eq!(q.as_ref().unwrap(), &2);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p: *mut isize = null_mut();
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert_eq!(p.as_ref(), None);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let q: *mut isize = &mut 2;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert_eq!(q.as_ref().unwrap(), &2);
|
|
|
|
|
|
|
|
|
|
// Lifetime inference
|
Add trivial cast lints.
This permits all coercions to be performed in casts, but adds lints to warn in those cases.
Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.
[breaking change]
* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:
```
let x = 42;
let y = &x as *const u32;
```
Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:
```
let x: u32 = 42;
let y = &x as *const u32;
```
2015-03-20 04:15:27 +00:00
|
|
|
|
let u = 2isize;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
{
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p = &u as *const isize;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert_eq!(p.as_ref().unwrap(), &2);
|
|
|
|
|
}
|
2017-09-29 19:36:32 +00:00
|
|
|
|
|
2017-09-30 21:45:18 +00:00
|
|
|
|
// Pointers to unsized types -- slices
|
2017-09-29 19:36:32 +00:00
|
|
|
|
let s: &mut [u8] = &mut [1, 2, 3];
|
|
|
|
|
let cs: *const [u8] = s;
|
|
|
|
|
assert_eq!(cs.as_ref(), Some(&*s));
|
|
|
|
|
|
|
|
|
|
let ms: *mut [u8] = s;
|
|
|
|
|
assert_eq!(ms.as_ref(), Some(&*s));
|
|
|
|
|
|
|
|
|
|
let cz: *const [u8] = &[];
|
|
|
|
|
assert_eq!(cz.as_ref(), Some(&[][..]));
|
|
|
|
|
|
|
|
|
|
let mz: *mut [u8] = &mut [];
|
|
|
|
|
assert_eq!(mz.as_ref(), Some(&[][..]));
|
|
|
|
|
|
2017-09-30 21:45:18 +00:00
|
|
|
|
let ncs: *const [u8] = null::<[u8; 3]>();
|
2017-09-29 19:36:32 +00:00
|
|
|
|
assert_eq!(ncs.as_ref(), None);
|
|
|
|
|
|
2017-09-30 21:45:18 +00:00
|
|
|
|
let nms: *mut [u8] = null_mut::<[u8; 3]>();
|
2017-09-29 19:36:32 +00:00
|
|
|
|
assert_eq!(nms.as_ref(), None);
|
2017-09-30 21:45:18 +00:00
|
|
|
|
|
|
|
|
|
// Pointers to unsized types -- trait objects
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let ci: *const dyn ToString = &3;
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(ci.as_ref().is_some());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let mi: *mut dyn ToString = &mut 3;
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(mi.as_ref().is_some());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let nci: *const dyn ToString = null::<isize>();
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(nci.as_ref().is_none());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let nmi: *mut dyn ToString = null_mut::<isize>();
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(nmi.as_ref().is_none());
|
2014-08-20 20:06:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_as_mut() {
|
|
|
|
|
unsafe {
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p: *mut isize = null_mut();
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert!(p.as_mut() == None);
|
|
|
|
|
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let q: *mut isize = &mut 2;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert!(q.as_mut().unwrap() == &mut 2);
|
|
|
|
|
|
|
|
|
|
// Lifetime inference
|
Add trivial cast lints.
This permits all coercions to be performed in casts, but adds lints to warn in those cases.
Part of this patch moves cast checking to a later stage of type checking. We acquire obligations to check casts as part of type checking where we previously checked them. Once we have type checked a function or module, then we check any cast obligations which have been acquired. That means we have more type information available to check casts (this was crucial to making coercions work properly in place of some casts), but it means that casts cannot feed input into type inference.
[breaking change]
* Adds two new lints for trivial casts and trivial numeric casts, these are warn by default, but can cause errors if you build with warnings as errors. Previously, trivial numeric casts and casts to trait objects were allowed.
* The unused casts lint has gone.
* Interactions between casting and type inference have changed in subtle ways. Two ways this might manifest are:
- You may need to 'direct' casts more with extra type information, for example, in some cases where `foo as _ as T` succeeded, you may now need to specify the type for `_`
- Casts do not influence inference of integer types. E.g., the following used to type check:
```
let x = 42;
let y = &x as *const u32;
```
Because the cast would inform inference that `x` must have type `u32`. This no longer applies and the compiler will fallback to `i32` for `x` and thus there will be a type error in the cast. The solution is to add more type information:
```
let x: u32 = 42;
let y = &x as *const u32;
```
2015-03-20 04:15:27 +00:00
|
|
|
|
let mut u = 2isize;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
{
|
2015-03-26 00:06:52 +00:00
|
|
|
|
let p = &mut u as *mut isize;
|
2014-08-20 20:06:34 +00:00
|
|
|
|
assert!(p.as_mut().unwrap() == &mut 2);
|
|
|
|
|
}
|
2017-09-29 19:36:32 +00:00
|
|
|
|
|
2017-09-30 21:45:18 +00:00
|
|
|
|
// Pointers to unsized types -- slices
|
2017-09-29 19:36:32 +00:00
|
|
|
|
let s: &mut [u8] = &mut [1, 2, 3];
|
|
|
|
|
let ms: *mut [u8] = s;
|
2019-08-05 13:30:08 +00:00
|
|
|
|
assert_eq!(ms.as_mut(), Some(&mut [1, 2, 3][..]));
|
2017-09-29 19:36:32 +00:00
|
|
|
|
|
|
|
|
|
let mz: *mut [u8] = &mut [];
|
|
|
|
|
assert_eq!(mz.as_mut(), Some(&mut [][..]));
|
|
|
|
|
|
2017-09-30 21:45:18 +00:00
|
|
|
|
let nms: *mut [u8] = null_mut::<[u8; 3]>();
|
2017-09-29 19:36:32 +00:00
|
|
|
|
assert_eq!(nms.as_mut(), None);
|
2017-09-30 21:45:18 +00:00
|
|
|
|
|
|
|
|
|
// Pointers to unsized types -- trait objects
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let mi: *mut dyn ToString = &mut 3;
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(mi.as_mut().is_some());
|
|
|
|
|
|
2018-07-13 05:25:22 +00:00
|
|
|
|
let nmi: *mut dyn ToString = null_mut::<isize>();
|
2017-09-30 21:45:18 +00:00
|
|
|
|
assert!(nmi.as_mut().is_none());
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_ptr_addition() {
|
|
|
|
|
unsafe {
|
2015-07-08 20:52:55 +00:00
|
|
|
|
let xs = vec![5; 16];
|
2014-06-28 20:57:36 +00:00
|
|
|
|
let mut ptr = xs.as_ptr();
|
|
|
|
|
let end = ptr.offset(16);
|
|
|
|
|
|
|
|
|
|
while ptr < end {
|
|
|
|
|
assert_eq!(*ptr, 5);
|
|
|
|
|
ptr = ptr.offset(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut xs_mut = xs;
|
|
|
|
|
let mut m_ptr = xs_mut.as_mut_ptr();
|
|
|
|
|
let m_end = m_ptr.offset(16);
|
|
|
|
|
|
|
|
|
|
while m_ptr < m_end {
|
|
|
|
|
*m_ptr += 5;
|
|
|
|
|
m_ptr = m_ptr.offset(1);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-08 20:52:55 +00:00
|
|
|
|
assert!(xs_mut == vec![10; 16]);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_ptr_subtraction() {
|
|
|
|
|
unsafe {
|
2019-12-07 04:18:12 +00:00
|
|
|
|
let xs = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
2015-03-03 08:42:26 +00:00
|
|
|
|
let mut idx = 9;
|
2014-06-28 20:57:36 +00:00
|
|
|
|
let ptr = xs.as_ptr();
|
|
|
|
|
|
2015-03-03 08:42:26 +00:00
|
|
|
|
while idx >= 0 {
|
2015-03-26 00:06:52 +00:00
|
|
|
|
assert_eq!(*(ptr.offset(idx as isize)), idx as isize);
|
2015-03-03 08:42:26 +00:00
|
|
|
|
idx = idx - 1;
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut xs_mut = xs;
|
|
|
|
|
let m_start = xs_mut.as_mut_ptr();
|
|
|
|
|
let mut m_ptr = m_start.offset(9);
|
|
|
|
|
|
2019-02-17 12:04:48 +00:00
|
|
|
|
loop {
|
2014-06-28 20:57:36 +00:00
|
|
|
|
*m_ptr += *m_ptr;
|
2019-02-17 12:04:48 +00:00
|
|
|
|
if m_ptr == m_start {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-06-28 20:57:36 +00:00
|
|
|
|
m_ptr = m_ptr.offset(-1);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-07 04:18:12 +00:00
|
|
|
|
assert_eq!(xs_mut, [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_set_memory() {
|
2014-12-30 08:19:41 +00:00
|
|
|
|
let mut xs = [0u8; 20];
|
2014-06-28 20:57:36 +00:00
|
|
|
|
let ptr = xs.as_mut_ptr();
|
2019-12-07 04:18:12 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
write_bytes(ptr, 5u8, xs.len());
|
|
|
|
|
}
|
2014-12-30 08:19:41 +00:00
|
|
|
|
assert!(xs == [5u8; 20]);
|
2014-06-28 20:57:36 +00:00
|
|
|
|
}
|
2015-02-10 13:37:44 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
2017-12-22 18:29:16 +00:00
|
|
|
|
fn test_unsized_nonnull() {
|
2017-04-04 16:31:38 +00:00
|
|
|
|
let xs: &[i32] = &[1, 2, 3];
|
2017-12-22 18:29:16 +00:00
|
|
|
|
let ptr = unsafe { NonNull::new_unchecked(xs as *const [i32] as *mut [i32]) };
|
2017-04-04 16:31:38 +00:00
|
|
|
|
let ys = unsafe { ptr.as_ref() };
|
|
|
|
|
let zs: &[i32] = &[1, 2, 3];
|
2015-02-10 13:37:44 +00:00
|
|
|
|
assert!(ys == zs);
|
|
|
|
|
}
|
2016-07-16 21:15:15 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
2016-08-29 19:31:28 +00:00
|
|
|
|
#[allow(warnings)]
|
|
|
|
|
// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
|
|
|
|
|
// ABI, or even point to an actual executable code, because the function itself is never invoked.
|
|
|
|
|
#[no_mangle]
|
|
|
|
|
pub fn test_variadic_fnptr() {
|
2016-07-16 21:15:15 +00:00
|
|
|
|
use core::hash::{Hash, SipHasher};
|
2019-12-07 04:18:12 +00:00
|
|
|
|
extern "C" {
|
2016-08-29 19:31:28 +00:00
|
|
|
|
fn test_variadic_fnptr(_: u64, ...) -> f64;
|
2016-07-16 21:15:15 +00:00
|
|
|
|
}
|
2019-12-07 04:18:12 +00:00
|
|
|
|
let p: unsafe extern "C" fn(u64, ...) -> f64 = test_variadic_fnptr;
|
2016-07-16 21:15:15 +00:00
|
|
|
|
let q = p.clone();
|
|
|
|
|
assert_eq!(p, q);
|
|
|
|
|
assert!(!(p < q));
|
|
|
|
|
let mut s = SipHasher::new();
|
|
|
|
|
assert_eq!(p.hash(&mut s), q.hash(&mut s));
|
|
|
|
|
}
|
2016-12-12 02:51:22 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn write_unaligned_drop() {
|
|
|
|
|
thread_local! {
|
|
|
|
|
static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Dropper(u32);
|
|
|
|
|
|
|
|
|
|
impl Drop for Dropper {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
DROPS.with(|d| d.borrow_mut().push(self.0));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let c = Dropper(0);
|
|
|
|
|
let mut t = Dropper(1);
|
2019-12-07 04:18:12 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
write_unaligned(&mut t, c);
|
|
|
|
|
}
|
2016-12-12 02:51:22 +00:00
|
|
|
|
}
|
|
|
|
|
DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
|
|
|
|
|
}
|
2018-04-29 14:09:56 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn align_offset_zst() {
|
|
|
|
|
// For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at
|
|
|
|
|
// all, because no amount of elements will align the pointer.
|
|
|
|
|
let mut p = 1;
|
|
|
|
|
while p < 1024 {
|
|
|
|
|
assert_eq!((p as *const ()).align_offset(p), 0);
|
|
|
|
|
if p != 1 {
|
|
|
|
|
assert_eq!(((p + 1) as *const ()).align_offset(p), !0);
|
|
|
|
|
}
|
|
|
|
|
p = (p + 1).next_power_of_two();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn align_offset_stride1() {
|
|
|
|
|
// For pointers of stride = 1, the pointer can always be aligned. The offset is equal to
|
|
|
|
|
// number of bytes.
|
|
|
|
|
let mut align = 1;
|
|
|
|
|
while align < 1024 {
|
2019-12-07 04:18:12 +00:00
|
|
|
|
for ptr in 1..2 * align {
|
2018-04-29 14:09:56 +00:00
|
|
|
|
let expected = ptr % align;
|
|
|
|
|
let offset = if expected == 0 { 0 } else { align - expected };
|
2019-12-07 04:18:12 +00:00
|
|
|
|
assert_eq!(
|
|
|
|
|
(ptr as *const u8).align_offset(align),
|
|
|
|
|
offset,
|
|
|
|
|
"ptr = {}, align = {}, size = 1",
|
|
|
|
|
ptr,
|
|
|
|
|
align
|
|
|
|
|
);
|
2018-04-29 14:09:56 +00:00
|
|
|
|
}
|
2018-05-17 15:02:47 +00:00
|
|
|
|
align = (align + 1).next_power_of_two();
|
2018-04-29 14:09:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn align_offset_weird_strides() {
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A3(u16, u8);
|
|
|
|
|
struct A4(u32);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A5(u32, u8);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A6(u32, u16);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A7(u32, u16, u8);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A8(u32, u32);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A9(u32, u32, u8);
|
|
|
|
|
#[repr(packed)]
|
|
|
|
|
struct A10(u32, u32, u16);
|
|
|
|
|
|
|
|
|
|
unsafe fn test_weird_stride<T>(ptr: *const T, align: usize) -> bool {
|
|
|
|
|
let numptr = ptr as usize;
|
2020-06-02 07:59:11 +00:00
|
|
|
|
let mut expected = usize::MAX;
|
2018-04-29 14:09:56 +00:00
|
|
|
|
// Naive but definitely correct way to find the *first* aligned element of stride::<T>.
|
|
|
|
|
for el in 0..align {
|
|
|
|
|
if (numptr + el * ::std::mem::size_of::<T>()) % align == 0 {
|
|
|
|
|
expected = el;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let got = ptr.align_offset(align);
|
|
|
|
|
if got != expected {
|
2019-12-07 04:18:12 +00:00
|
|
|
|
eprintln!(
|
|
|
|
|
"aligning {:p} (with stride of {}) to {}, expected {}, got {}",
|
|
|
|
|
ptr,
|
|
|
|
|
::std::mem::size_of::<T>(),
|
|
|
|
|
align,
|
|
|
|
|
expected,
|
|
|
|
|
got
|
|
|
|
|
);
|
2018-04-29 14:09:56 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For pointers of stride != 1, we verify the algorithm against the naivest possible
|
|
|
|
|
// implementation
|
|
|
|
|
let mut align = 1;
|
|
|
|
|
let mut x = false;
|
2020-08-19 07:56:38 +00:00
|
|
|
|
// Miri is too slow
|
|
|
|
|
let limit = if cfg!(miri) { 32 } else { 1024 };
|
|
|
|
|
while align < limit {
|
2019-12-07 04:18:12 +00:00
|
|
|
|
for ptr in 1usize..4 * align {
|
2018-04-29 14:09:56 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
x |= test_weird_stride::<A3>(ptr as *const A3, align);
|
|
|
|
|
x |= test_weird_stride::<A4>(ptr as *const A4, align);
|
|
|
|
|
x |= test_weird_stride::<A5>(ptr as *const A5, align);
|
|
|
|
|
x |= test_weird_stride::<A6>(ptr as *const A6, align);
|
|
|
|
|
x |= test_weird_stride::<A7>(ptr as *const A7, align);
|
|
|
|
|
x |= test_weird_stride::<A8>(ptr as *const A8, align);
|
|
|
|
|
x |= test_weird_stride::<A9>(ptr as *const A9, align);
|
|
|
|
|
x |= test_weird_stride::<A10>(ptr as *const A10, align);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
align = (align + 1).next_power_of_two();
|
|
|
|
|
}
|
|
|
|
|
assert!(!x);
|
|
|
|
|
}
|
2020-11-22 08:08:04 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn offset_from() {
|
|
|
|
|
let mut a = [0; 5];
|
|
|
|
|
let ptr1: *mut i32 = &mut a[1];
|
|
|
|
|
let ptr2: *mut i32 = &mut a[3];
|
|
|
|
|
unsafe {
|
|
|
|
|
assert_eq!(ptr2.offset_from(ptr1), 2);
|
|
|
|
|
assert_eq!(ptr1.offset_from(ptr2), -2);
|
|
|
|
|
assert_eq!(ptr1.offset(2), ptr2);
|
|
|
|
|
assert_eq!(ptr2.offset(-2), ptr1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-19 13:38:11 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn ptr_metadata() {
|
|
|
|
|
struct Unit;
|
|
|
|
|
struct Pair<A, B: ?Sized>(A, B);
|
|
|
|
|
extern "C" {
|
|
|
|
|
type Extern;
|
|
|
|
|
}
|
|
|
|
|
let () = metadata(&());
|
|
|
|
|
let () = metadata(&Unit);
|
|
|
|
|
let () = metadata(&4_u32);
|
|
|
|
|
let () = metadata(&String::new());
|
|
|
|
|
let () = metadata(&Some(4_u32));
|
|
|
|
|
let () = metadata(&ptr_metadata);
|
|
|
|
|
let () = metadata(&|| {});
|
|
|
|
|
let () = metadata(&[4, 7]);
|
|
|
|
|
let () = metadata(&(4, String::new()));
|
|
|
|
|
let () = metadata(&Pair(4, String::new()));
|
|
|
|
|
let () = metadata(0 as *const Extern);
|
|
|
|
|
let () = metadata(0 as *const <&u32 as std::ops::Deref>::Target);
|
|
|
|
|
|
|
|
|
|
assert_eq!(metadata("foo"), 3_usize);
|
|
|
|
|
assert_eq!(metadata(&[4, 7][..]), 2_usize);
|
|
|
|
|
|
|
|
|
|
let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]);
|
|
|
|
|
let dst_struct: &Pair<bool, [u8]> = &Pair(true, [0x66, 0x6F, 0x6F]);
|
|
|
|
|
assert_eq!(metadata(dst_tuple), 3_usize);
|
|
|
|
|
assert_eq!(metadata(dst_struct), 3_usize);
|
|
|
|
|
unsafe {
|
|
|
|
|
let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple);
|
|
|
|
|
let dst_struct: &Pair<bool, str> = std::mem::transmute(dst_struct);
|
|
|
|
|
assert_eq!(&dst_tuple.1, "foo");
|
|
|
|
|
assert_eq!(&dst_struct.1, "foo");
|
|
|
|
|
assert_eq!(metadata(dst_tuple), 3_usize);
|
|
|
|
|
assert_eq!(metadata(dst_struct), 3_usize);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-29 17:31:22 +00:00
|
|
|
|
let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
|
|
|
|
|
let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
|
|
|
|
|
let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
|
|
|
|
|
let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
|
|
|
|
|
let vtable_5: DynMetadata<dyn Display> =
|
|
|
|
|
metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
|
2020-10-19 13:38:11 +00:00
|
|
|
|
unsafe {
|
|
|
|
|
let address_1: usize = std::mem::transmute(vtable_1);
|
|
|
|
|
let address_2: usize = std::mem::transmute(vtable_2);
|
|
|
|
|
let address_3: usize = std::mem::transmute(vtable_3);
|
|
|
|
|
let address_4: usize = std::mem::transmute(vtable_4);
|
2020-12-29 17:31:22 +00:00
|
|
|
|
let address_5: usize = std::mem::transmute(vtable_5);
|
|
|
|
|
// Different trait => different vtable pointer
|
|
|
|
|
assert_ne!(address_1, address_2);
|
|
|
|
|
// Different erased type => different vtable pointer
|
|
|
|
|
assert_ne!(address_2, address_3);
|
|
|
|
|
// Same erased type and same trait => same vtable pointer
|
|
|
|
|
assert_eq!(address_3, address_4);
|
|
|
|
|
assert_eq!(address_3, address_5);
|
2020-10-19 13:38:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn ptr_metadata_bounds() {
|
|
|
|
|
fn metadata_eq_method_address<T: ?Sized>() -> usize {
|
|
|
|
|
// The `Metadata` associated type has an `Ord` bound, so this is valid:
|
|
|
|
|
<<T as Pointee>::Metadata as PartialEq>::eq as usize
|
|
|
|
|
}
|
|
|
|
|
// "Synthetic" trait impls generated by the compiler like those of `Pointee`
|
|
|
|
|
// are not checked for bounds of associated type.
|
|
|
|
|
// So with a buggy libcore we could have both:
|
|
|
|
|
// * `<dyn Display as Pointee>::Metadata == DynMetadata`
|
|
|
|
|
// * `DynMetadata: !PartialEq`
|
|
|
|
|
// … and cause an ICE here:
|
|
|
|
|
metadata_eq_method_address::<dyn Display>();
|
|
|
|
|
|
|
|
|
|
// For this reason, let’s check here that bounds are satisfied:
|
|
|
|
|
|
2020-12-29 17:31:22 +00:00
|
|
|
|
let _ = static_assert_expected_bounds_for_metadata::<()>;
|
|
|
|
|
let _ = static_assert_expected_bounds_for_metadata::<usize>;
|
|
|
|
|
let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
|
|
|
|
|
fn _static_assert_associated_type<T: ?Sized>() {
|
|
|
|
|
let _ = static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>;
|
2020-10-19 13:38:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn static_assert_expected_bounds_for_metadata<Meta>()
|
|
|
|
|
where
|
|
|
|
|
// Keep this in sync with the associated type in `library/core/src/ptr/metadata.rs`
|
|
|
|
|
Meta: Copy + Send + Sync + Ord + std::hash::Hash + Unpin,
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-13 10:09:15 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn dyn_metadata() {
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
#[repr(align(32))]
|
|
|
|
|
struct Something([u8; 47]);
|
|
|
|
|
|
|
|
|
|
let value = Something([0; 47]);
|
|
|
|
|
let trait_object: &dyn Debug = &value;
|
|
|
|
|
let meta = metadata(trait_object);
|
|
|
|
|
|
|
|
|
|
assert_eq!(meta.size_of(), 64);
|
|
|
|
|
assert_eq!(meta.size_of(), std::mem::size_of::<Something>());
|
|
|
|
|
assert_eq!(meta.align_of(), 32);
|
|
|
|
|
assert_eq!(meta.align_of(), std::mem::align_of::<Something>());
|
|
|
|
|
assert_eq!(meta.layout(), std::alloc::Layout::new::<Something>());
|
|
|
|
|
|
|
|
|
|
assert!(format!("{:?}", meta).starts_with("DynMetadata(0x"));
|
|
|
|
|
}
|
2021-01-18 15:19:29 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn from_raw_parts() {
|
|
|
|
|
let mut value = 5_u32;
|
|
|
|
|
let address = &mut value as *mut _ as *mut ();
|
|
|
|
|
let trait_object: &dyn Display = &mut value;
|
|
|
|
|
let vtable = metadata(trait_object);
|
|
|
|
|
let trait_object = NonNull::from(trait_object);
|
|
|
|
|
|
|
|
|
|
assert_eq!(ptr::from_raw_parts(address, vtable), trait_object.as_ptr());
|
|
|
|
|
assert_eq!(ptr::from_raw_parts_mut(address, vtable), trait_object.as_ptr());
|
|
|
|
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), vtable), trait_object);
|
|
|
|
|
|
|
|
|
|
let mut array = [5_u32, 5, 5, 5, 5];
|
|
|
|
|
let address = &mut array as *mut _ as *mut ();
|
|
|
|
|
let array_ptr = NonNull::from(&mut array);
|
|
|
|
|
let slice_ptr = NonNull::from(&mut array[..]);
|
|
|
|
|
|
|
|
|
|
assert_eq!(ptr::from_raw_parts(address, ()), array_ptr.as_ptr());
|
|
|
|
|
assert_eq!(ptr::from_raw_parts_mut(address, ()), array_ptr.as_ptr());
|
|
|
|
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), ()), array_ptr);
|
|
|
|
|
|
|
|
|
|
assert_eq!(ptr::from_raw_parts(address, 5), slice_ptr.as_ptr());
|
|
|
|
|
assert_eq!(ptr::from_raw_parts_mut(address, 5), slice_ptr.as_ptr());
|
|
|
|
|
assert_eq!(NonNull::from_raw_parts(NonNull::new(address).unwrap(), 5), slice_ptr);
|
|
|
|
|
}
|
2021-01-18 21:24:33 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn thin_box() {
|
|
|
|
|
let foo = ThinBox::<dyn Display>::new(4);
|
|
|
|
|
assert_eq!(foo.to_string(), "4");
|
|
|
|
|
drop(foo);
|
|
|
|
|
let bar = ThinBox::<dyn Display>::new(7);
|
|
|
|
|
assert_eq!(bar.to_string(), "7");
|
|
|
|
|
|
|
|
|
|
// A slightly more interesting library that could be built on top of metadata APIs.
|
|
|
|
|
//
|
|
|
|
|
// * It could be generalized to any `T: ?Sized` (not just trait object)
|
|
|
|
|
// if `{size,align}_of_for_meta<T: ?Sized>(T::Metadata)` are added.
|
|
|
|
|
// * Constructing a `ThinBox` without consuming and deallocating a `Box`
|
|
|
|
|
// requires either the unstable `Unsize` marker trait,
|
|
|
|
|
// or the unstable `unsized_locals` language feature,
|
|
|
|
|
// or taking `&dyn T` and restricting to `T: Copy`.
|
|
|
|
|
|
|
|
|
|
use std::alloc::*;
|
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
|
|
struct ThinBox<T>
|
|
|
|
|
where
|
|
|
|
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
|
|
|
|
{
|
|
|
|
|
ptr: NonNull<DynMetadata<T>>,
|
|
|
|
|
phantom: PhantomData<T>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> ThinBox<T>
|
|
|
|
|
where
|
|
|
|
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
|
|
|
|
{
|
|
|
|
|
pub fn new<Value: std::marker::Unsize<T>>(value: Value) -> Self {
|
|
|
|
|
let unsized_: &T = &value;
|
|
|
|
|
let meta = metadata(unsized_);
|
|
|
|
|
let meta_layout = Layout::for_value(&meta);
|
|
|
|
|
let value_layout = Layout::for_value(&value);
|
|
|
|
|
let (layout, offset) = meta_layout.extend(value_layout).unwrap();
|
|
|
|
|
// `DynMetadata` is pointer-sized:
|
|
|
|
|
assert!(layout.size() > 0);
|
|
|
|
|
// If `ThinBox<T>` is generalized to any `T: ?Sized`,
|
|
|
|
|
// handle ZSTs with a dangling pointer without going through `alloc()`,
|
|
|
|
|
// like `Box<T>` does.
|
|
|
|
|
unsafe {
|
|
|
|
|
let ptr = NonNull::new(alloc(layout))
|
|
|
|
|
.unwrap_or_else(|| handle_alloc_error(layout))
|
|
|
|
|
.cast::<DynMetadata<T>>();
|
|
|
|
|
ptr.as_ptr().write(meta);
|
|
|
|
|
ptr.cast::<u8>().as_ptr().add(offset).cast::<Value>().write(value);
|
|
|
|
|
Self { ptr, phantom: PhantomData }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn meta(&self) -> DynMetadata<T> {
|
|
|
|
|
unsafe { *self.ptr.as_ref() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn layout(&self) -> (Layout, usize) {
|
|
|
|
|
let meta = self.meta();
|
|
|
|
|
Layout::for_value(&meta).extend(meta.layout()).unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn value_ptr(&self) -> *const T {
|
|
|
|
|
let (_, offset) = self.layout();
|
|
|
|
|
let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
|
|
|
|
|
ptr::from_raw_parts(data_ptr.cast(), self.meta())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn value_mut_ptr(&mut self) -> *mut T {
|
|
|
|
|
let (_, offset) = self.layout();
|
|
|
|
|
// FIXME: can this line be shared with the same in `value_ptr()`
|
|
|
|
|
// without upsetting Stacked Borrows?
|
|
|
|
|
let data_ptr = unsafe { self.ptr.cast::<u8>().as_ptr().add(offset) };
|
|
|
|
|
from_raw_parts_mut(data_ptr.cast(), self.meta())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> std::ops::Deref for ThinBox<T>
|
|
|
|
|
where
|
|
|
|
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
|
|
|
|
{
|
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
|
|
fn deref(&self) -> &T {
|
|
|
|
|
unsafe { &*self.value_ptr() }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> std::ops::DerefMut for ThinBox<T>
|
|
|
|
|
where
|
|
|
|
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
|
|
|
|
{
|
|
|
|
|
fn deref_mut(&mut self) -> &mut T {
|
|
|
|
|
unsafe { &mut *self.value_mut_ptr() }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> std::ops::Drop for ThinBox<T>
|
|
|
|
|
where
|
|
|
|
|
T: ?Sized + Pointee<Metadata = DynMetadata<T>>,
|
|
|
|
|
{
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
let (layout, _) = self.layout();
|
|
|
|
|
unsafe {
|
|
|
|
|
drop_in_place::<T>(&mut **self);
|
|
|
|
|
dealloc(self.ptr.cast().as_ptr(), layout);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|