Skip to content

Commit db24440

Browse files
committed
Move mutable rvalue promotion to alternative section
1 parent 1d9f541 commit db24440

File tree

1 file changed

+44
-35
lines changed

1 file changed

+44
-35
lines changed

text/0000-rvalue_static_promotion.md

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,11 @@ fn generic<T>() -> &'static Option<T> {
4545
}
4646
```
4747

48-
Additionally, despite it being memory safe, it is not currently possible to
49-
create a `&'static mut` to a zero-sized type without involving unsafe code:
50-
51-
```rust
52-
fn return_fn_mut_or_default(&mut self) -> &FnMut(u32, u32) -> u32 {
53-
// error: references in constants may only refer to immutable values
54-
const STATIC_TRAIT_OBJECT: &'static mut FnMut(u32, u32) -> u32
55-
= &mut |x, y| x * y;
56-
57-
self.operator.unwrap_or(STATIC_TRAIT_OBJECT)
58-
}
59-
```
60-
61-
Lastly, the compiler already special cases a small subset of rvalue
48+
However, the compiler already special cases a small subset of rvalue
6249
const expressions to have static lifetime - namely the empty array expression:
6350

6451
```rust
6552
let x: &'static [u8] = &[];
66-
let y: &'static mut [u8] = &mut [];
6753
```
6854

6955
And though they don't have to be seen as such, string literals could be regarded
@@ -94,22 +80,8 @@ Inside a function body's block:
9480
it into a static memory location and give the resulting reference a
9581
`'static` lifetime.
9682

97-
Likewise,
98-
99-
- If a mutable reference to a constexpr rvalue is taken. (`&mut <constexpr>`)
100-
- And the constexpr does not contain a `UnsafeCell { ... }` constructor.
101-
- And the constexpr does not contain a const fn call returning a type containing a `UnsafeCell`.
102-
- _And the type of the rvalue is zero-sized._
103-
- Then instead of translating the value into a stack slot, translate
104-
it into a static memory location and give the resulting reference a
105-
`'static` lifetime.
106-
10783
The `UnsafeCell` restrictions are there to ensure that the promoted value is
108-
truly immutable behind the reference (Though not technically needed in the zero-sized case, see alternatives below).
109-
110-
The zero-sized restriction for mutable references is there because
111-
aliasing mutable references are only safe for zero sized types
112-
(since you never dereference the pointer for them).
84+
truly immutable behind the reference.
11385

11486
Examples:
11587

@@ -119,9 +91,6 @@ let a: &'static u32 = &32;
11991
let b: &'static Option<UnsafeCell<u32>> = &None;
12092
let c: &'static Fn() -> u32 = &|| 42;
12193

122-
let d: &'static mut () = &mut ();
123-
let e: &'static mut Fn() -> u32 = &mut || 42;
124-
12594
let h: &'static u32 = &(32 + 64);
12695

12796
fn generic<T>() -> &'static Option<T> {
@@ -134,7 +103,7 @@ let g: &'static Cell<u32> = &Cell::new(); // assuming conf fn new()
134103
```
135104

136105
These rules above should be consistent with the existing rvalue promotions in `const`
137-
initializer lists:
106+
initializer expressions:
138107

139108
```rust
140109
// If this compiles:
@@ -160,9 +129,49 @@ https://github.com/rust-lang/rust/blob/29ea4eef9fa6e36f40bc1f31eb1e56bf5941ee72/
160129

161130
One more feature with seemingly ad-hoc rules to complicate the language...
162131

163-
# Alternatives
132+
# Alternatives, Extensions
164133
[alternatives]: #alternatives
165134

135+
It would be possible to extend support to `&'static mut` references,
136+
as long as there is the additional constraint that the
137+
referenced type is zero sized.
138+
139+
This again has precedence in the array reference constructor:
140+
141+
```rust
142+
// valid code today
143+
let y: &'static mut [u8] = &mut [];
144+
```
145+
146+
The rules would be similar:
147+
148+
- If a mutable reference to a constexpr rvalue is taken. (`&mut <constexpr>`)
149+
- And the constexpr does not contain a `UnsafeCell { ... }` constructor.
150+
- And the constexpr does not contain a const fn call returning a type containing a `UnsafeCell`.
151+
- _And the type of the rvalue is zero-sized._
152+
- Then instead of translating the value into a stack slot, translate
153+
it into a static memory location and give the resulting reference a
154+
`'static` lifetime.
155+
156+
The zero-sized restriction is there because
157+
aliasing mutable references are only safe for zero sized types
158+
(since you never dereference the pointer for them).
159+
160+
Example:
161+
162+
```rust
163+
fn return_fn_mut_or_default(&mut self) -> &FnMut(u32, u32) -> u32 {
164+
self.operator.unwrap_or(&mut |x, y| x * y)
165+
// ^ would be okay, since it would be translated like this:
166+
// const STATIC_TRAIT_OBJECT: &'static mut FnMut(u32, u32) -> u32
167+
// = &mut |x, y| x * y;
168+
// self.operator.unwrap_or(STATIC_TRAIT_OBJECT)
169+
}
170+
171+
let d: &'static mut () = &mut ();
172+
let e: &'static mut Fn() -> u32 = &mut || 42;
173+
```
174+
166175
There are two ways this could be taken further with zero-sized types:
167176

168177
1. Remove the `UnsafeCell` restriction if the type of the rvalue is zero-sized.

0 commit comments

Comments
 (0)