From 7e95f10f06b1f9cb5a9b1e3aa7b9285de5996f78 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Thu, 5 May 2022 17:31:39 -0500 Subject: [PATCH 1/5] Clarify casting of pointers-to-unsized --- src/expressions/operator-expr.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index d8658d647..3754b2279 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -440,6 +440,27 @@ Casts an enum to its discriminant, then uses a numeric cast if needed. Casts to the `char` with the corresponding code point. +#### Pointer to pointer cast + +Casting from a pointer to unsized type to pointer to sized type discards the pointer metadata, resulting in just a pointer to the referenced memory. +Casting between pointers to unsized type preserves the pointer metadata unchanged (e.g. the slice element length remains the same). + +To illustrate: + +```rust +#![feature(ptr_metadata)] +use std::ptr; + +let u8_slice_ptr = ptr::slice_from_raw_parts::(ptr::null(), 4); +assert_eq!((ptr::null(), 4), u8_slice_ptr.to_raw_parts()); + +let u8_ptr = u8_slice_ptr as *const u8; +assert_eq!((ptr::null(), ()), u8_ptr.to_raw_parts()); + +let u16_slice_ptr = u8_slice_ptr as *const [u16]; +assert_eq!((ptr::null(), 4), u16_slice_ptr.to_raw_parts()); +``` + #### Pointer to address cast Casting from a raw pointer to an integer produces the machine address of the referenced memory. From 64269668e682574bc9d72d09e6670fef2ef8a44a Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Mon, 1 Aug 2022 22:05:56 -0400 Subject: [PATCH 2/5] Use stable example --- src/expressions/operator-expr.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 3754b2279..ab99bf856 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -448,17 +448,18 @@ Casting between pointers to unsized type preserves the pointer metadata unchange To illustrate: ```rust -#![feature(ptr_metadata)] -use std::ptr; +let u32_slice: &[u16] = &[0, 1, 2, 3][..]; + +let u32_slice_ptr = u16_slice as *const [u32]; +let u16_slice_ptr = u8_slice as *const [u16]; -let u8_slice_ptr = ptr::slice_from_raw_parts::(ptr::null(), 4); -assert_eq!((ptr::null(), 4), u8_slice_ptr.to_raw_parts()); +assert_eq!(u16_slice_ptr as *const (), u32_slice_ptr as *const ()); -let u8_ptr = u8_slice_ptr as *const u8; -assert_eq!((ptr::null(), ()), u8_ptr.to_raw_parts()); +assert_eq!(unsafe { (&*u16_slice_ptr).len() }, 4); +assert_eq!(unsafe { (&*u32_slice_ptr).len() }, 4); -let u16_slice_ptr = u8_slice_ptr as *const [u16]; -assert_eq!((ptr::null(), 4), u16_slice_ptr.to_raw_parts()); +assert_eq!(unsafe { std::mem::size_of_val(&*u16_slice_ptr) }, 4 * 2); +assert_eq!(unsafe { std::mem::size_of_val(&*u32_slice_ptr) }, 4 * 4); ``` #### Pointer to address cast From d19bbeed512d8931eb09d81230c0f1cd029009b6 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Mon, 1 Aug 2022 22:11:51 -0400 Subject: [PATCH 3/5] Update src/expressions/operator-expr.md --- src/expressions/operator-expr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index ab99bf856..f81e9129d 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -450,8 +450,8 @@ To illustrate: ```rust let u32_slice: &[u16] = &[0, 1, 2, 3][..]; -let u32_slice_ptr = u16_slice as *const [u32]; -let u16_slice_ptr = u8_slice as *const [u16]; +let u32_slice_ptr = u32_slice as *const [u32]; +let u16_slice_ptr = u32_slice_ptr as *const [u16]; assert_eq!(u16_slice_ptr as *const (), u32_slice_ptr as *const ()); From 89f98b5ddd54fb16ae53a364af128bb371209c7a Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Mon, 1 Aug 2022 22:26:51 -0400 Subject: [PATCH 4/5] Update operator-expr.md --- src/expressions/operator-expr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index f81e9129d..01bb670f0 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -448,7 +448,7 @@ Casting between pointers to unsized type preserves the pointer metadata unchange To illustrate: ```rust -let u32_slice: &[u16] = &[0, 1, 2, 3][..]; +let u32_slice: &[u32] = &[0, 1, 2, 3][..]; let u32_slice_ptr = u32_slice as *const [u32]; let u16_slice_ptr = u32_slice_ptr as *const [u16]; From 8b2ea7cd7314c25d193fdc9d82aa6ae159bc0db5 Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Sat, 13 Aug 2022 00:12:37 -0500 Subject: [PATCH 5/5] Note *const [_] as *const dyn _ is an error --- src/expressions/operator-expr.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 01bb670f0..3b7b574e1 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -444,6 +444,7 @@ Casts to the `char` with the corresponding code point. Casting from a pointer to unsized type to pointer to sized type discards the pointer metadata, resulting in just a pointer to the referenced memory. Casting between pointers to unsized type preserves the pointer metadata unchanged (e.g. the slice element length remains the same). +If the pointer metadata type does not match (e.g. casting between slice and vtable pointers), a compile error is produced. To illustrate: @@ -460,6 +461,9 @@ assert_eq!(unsafe { (&*u32_slice_ptr).len() }, 4); assert_eq!(unsafe { std::mem::size_of_val(&*u16_slice_ptr) }, 4 * 2); assert_eq!(unsafe { std::mem::size_of_val(&*u32_slice_ptr) }, 4 * 4); + +// ERROR: +// u32_slice_ptr as *const dyn Sized; ``` #### Pointer to address cast