From f73f6d6f023ef5af48adab6b20accb48eef7ef61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2024 13:41:13 +0200 Subject: [PATCH 1/3] operator expressions: add &raw --- src/expressions.md | 4 ++-- src/expressions/operator-expr.md | 26 ++++++++++++-------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 208ac9506..75c9834b7 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -146,7 +146,7 @@ A *value expression* is an expression that represents an actual value. The following contexts are *place expression* contexts: * The left operand of a [compound assignment] expression. -* The operand of a unary [borrow], [address-of][addr-of] or [dereference][deref] operator. +* The operand of a unary [borrow], [raw borrow][raw-borrow] or [dereference][deref] operator. * The operand of a field expression. * The indexed operand of an array indexing expression. * The operand of any [implicit borrow]. @@ -276,7 +276,7 @@ They are never allowed before: [assign]: expressions/operator-expr.md#assignment-expressions [borrow]: expressions/operator-expr.md#borrow-operators -[addr-of]: expressions/operator-expr.md#raw-address-of-operators +[raw-borrow]: expressions/operator-expr.md#raw-borrow-operators [comparison]: expressions/operator-expr.md#comparison-operators [compound assignment]: expressions/operator-expr.md#compound-assignment-expressions [deref]: expressions/operator-expr.md#the-dereference-operator diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 0601a8622..ea3984158 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -41,7 +41,9 @@ The following things are considered to be overflow: > **Syntax**\ > _BorrowExpression_ :\ >       (`&`|`&&`) [_Expression_]\ ->    | (`&`|`&&`) `mut` [_Expression_] +>    | (`&`|`&&`) `mut` [_Expression_]\ +>    | (`&`|`&&`) `raw` `const` [_Expression_]\ +>    | (`&`|`&&`) `raw` `mut` [_Expression_] The `&` (shared borrow) and `&mut` (mutable borrow) operators are unary prefix operators. When applied to a [place expression], this expressions produces a reference (pointer) to the location that the value refers to. @@ -79,20 +81,18 @@ let a = && && mut 10; let a = & & & & mut 10; ``` -### Raw address-of operators +### Raw borrow operators -Related to the borrow operators are the *raw address-of operators*, which do not have first-class syntax, but are exposed via the macros [`ptr::addr_of!(expr)`][addr_of] and [`ptr::addr_of_mut!(expr)`][addr_of_mut]. -The expression `expr` is evaluated in place expression context. -`ptr::addr_of!(expr)` then creates a const raw pointer of type `*const T` to the given place, and `ptr::addr_of_mut!(expr)` creates a mutable raw pointer of type `*mut T`. +`&raw const` and `&raw mut` are the *raw borrow operators*. +The operand expression of these operators is evaluated in place expression context. +`&raw const expr` then creates a const raw pointer of type `*const T` to the given place, and `&raw mut expr` creates a mutable raw pointer of type `*mut T`. -The raw address-of operators must be used instead of a borrow operator whenever the place expression could evaluate to a place that is not properly aligned or does not store a valid value as determined by its type, or whenever creating a reference would introduce incorrect aliasing assumptions. -In those situations, using a borrow operator would cause [undefined behavior] by creating an invalid reference, but a raw pointer may still be constructed using an address-of operator. +The raw borrow operators must be used instead of a borrow operator whenever the place expression could evaluate to a place that is not properly aligned or does not store a valid value as determined by its type, or whenever creating a reference would introduce incorrect aliasing assumptions. +In those situations, using a borrow operator would cause [undefined behavior] by creating an invalid reference, but a raw pointer may still be constructed. The following is an example of creating a raw pointer to an unaligned place through a `packed` struct: ```rust -use std::ptr; - #[repr(packed)] struct Packed { f1: u8, @@ -101,14 +101,14 @@ struct Packed { let packed = Packed { f1: 1, f2: 2 }; // `&packed.f2` would create an unaligned reference, and thus be undefined behavior! -let raw_f2 = ptr::addr_of!(packed.f2); +let raw_f2 = &raw const packed.f2; assert_eq!(unsafe { raw_f2.read_unaligned() }, 2); ``` The following is an example of creating a raw pointer to a place that does not contain a valid value: ```rust -use std::{ptr, mem::MaybeUninit}; +use std::mem::MaybeUninit; struct Demo { field: bool, @@ -117,7 +117,7 @@ struct Demo { let mut uninit = MaybeUninit::::uninit(); // `&uninit.as_mut().field` would create a reference to an uninitialized `bool`, // and thus be undefined behavior! -let f1_ptr = unsafe { ptr::addr_of_mut!((*uninit.as_mut_ptr()).field) }; +let f1_ptr = unsafe { &raw mut (*uninit.as_mut_ptr()).field }; unsafe { f1_ptr.write(true); } let init = unsafe { uninit.assume_init() }; ``` @@ -674,8 +674,6 @@ See [this test] for an example of using this dependency. [Function pointer]: ../types/function-pointer.md [Function item]: ../types/function-item.md [undefined behavior]: ../behavior-considered-undefined.md -[addr_of]: std::ptr::addr_of -[addr_of_mut]: std::ptr::addr_of_mut [_BorrowExpression_]: #borrow-operators [_DereferenceExpression_]: #the-dereference-operator From 060d2b35cecf93bfd7fa20faa6c7f9b6aa1bc89f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Aug 2024 10:44:07 +0200 Subject: [PATCH 2/3] use &raw instead of addr_of macros --- src/behavior-considered-undefined.md | 2 +- src/items/static-items.md | 2 +- src/type-layout.md | 4 ++-- src/types/pointer.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 14d8edeff..e7fa1a0db 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -102,7 +102,7 @@ the pointer that was dereferenced, *not* the type of the field that is being accessed. Note that a place based on a misaligned pointer only leads to undefined behavior -when it is loaded from or stored to. `addr_of!`/`addr_of_mut!` on such a place +when it is loaded from or stored to. `&raw const`/`&raw mut` on such a place is allowed. `&`/`&mut` on a place requires the alignment of the field type (or else the program would be "producing an invalid value"), which generally is a less restrictive requirement than being based on an aligned pointer. Taking a diff --git a/src/items/static-items.md b/src/items/static-items.md index f00f1aab8..f688a9024 100644 --- a/src/items/static-items.md +++ b/src/items/static-items.md @@ -117,7 +117,7 @@ unsafe fn bump_levels_unsafe() -> u32 { // must still guard against concurrent access. fn bump_levels_safe() -> u32 { unsafe { - return atomic_add(std::ptr::addr_of_mut!(LEVELS), 1); + return atomic_add(&raw mut LEVELS, 1); } } ``` diff --git a/src/type-layout.md b/src/type-layout.md index 8b1a689d8..b91674fa1 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -575,9 +575,9 @@ was wrapped in a newtype `struct` with the same `align` modifier. > println!("{}", {e.f2}); > // Or if you need a pointer, use the unaligned methods for reading and writing > // instead of dereferencing the pointer directly. -> let ptr: *const u16 = std::ptr::addr_of!(e.f2); +> let ptr: *const u16 = &raw const e.f2; > let value = unsafe { ptr.read_unaligned() }; -> let mut_ptr: *mut u16 = std::ptr::addr_of_mut!(e.f2); +> let mut_ptr: *mut u16 = &raw mut e.f2; > unsafe { mut_ptr.write_unaligned(3) } > ``` diff --git a/src/types/pointer.md b/src/types/pointer.md index a1ec509c3..7299ce75e 100644 --- a/src/types/pointer.md +++ b/src/types/pointer.md @@ -44,7 +44,7 @@ they exist to support interoperability with foreign code, and writing performanc When comparing raw pointers they are compared by their address, rather than by what they point to. When comparing raw pointers to [dynamically sized types] they also have their additional data compared. -Raw pointers can be created directly using [`core::ptr::addr_of!`] for `*const` pointers and [`core::ptr::addr_of_mut!`] for `*mut` pointers. +Raw pointers can be created directly using `&raw const` for `*const` pointers and `&raw mut` for `*mut` pointers. ## Smart Pointers From 60ccf42d69d4378437afa9d35b6b95394649735c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2024 12:40:15 +0200 Subject: [PATCH 3/3] markdown anchor tweaks --- src/expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 75c9834b7..1ee015f07 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -146,7 +146,7 @@ A *value expression* is an expression that represents an actual value. The following contexts are *place expression* contexts: * The left operand of a [compound assignment] expression. -* The operand of a unary [borrow], [raw borrow][raw-borrow] or [dereference][deref] operator. +* The operand of a unary [borrow], [raw borrow] or [dereference][deref] operator. * The operand of a field expression. * The indexed operand of an array indexing expression. * The operand of any [implicit borrow]. @@ -276,7 +276,6 @@ They are never allowed before: [assign]: expressions/operator-expr.md#assignment-expressions [borrow]: expressions/operator-expr.md#borrow-operators -[raw-borrow]: expressions/operator-expr.md#raw-borrow-operators [comparison]: expressions/operator-expr.md#comparison-operators [compound assignment]: expressions/operator-expr.md#compound-assignment-expressions [deref]: expressions/operator-expr.md#the-dereference-operator @@ -294,6 +293,7 @@ They are never allowed before: [Mutable `static` items]: items/static-items.md#mutable-statics [scrutinee]: glossary.md#scrutinee [promoted]: destructors.md#constant-promotion +[raw borrow]: expressions/operator-expr.md#raw-borrow-operators [slice]: types/slice.md [statement]: statements.md [static variables]: items/static-items.md