diff --git a/src/expressions.md b/src/expressions.md index 9e10dcea3..7ebd79e16 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 pointer][raw-ptr-to] 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-ptr-to]: expressions/operator-expr.md#raw-pointer-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 d3fa33b81..d37d07fd6 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 pointer 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]. +Related to the borrow operators are the *raw pointer operators*, `&raw const` and `&raw 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 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 pointer 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() }; ```