Skip to content

Commit 7acafcd

Browse files
committed
Describe why certain constants aren't accepted
We had described the design rationale for why certain values of constant items were accepted, but for the values that are not accepted, while we had described mechanically the reasons for this, we had not described the rationale for it. This can be a bit tricky, because often the real rationale is that "we're being conservative and only allowing the cases where we have a good reason to allow them and where we can prove that allowing them is OK". So it is easier to describe why we allow something than why we don't. But still, let's try to describe some reasons why we don't allow some things yet.
1 parent 7d0932d commit 7acafcd

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

src/items/constant-items.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ const _: &mut u8 = unsafe { &mut S }; // ERROR.
7676
// Not allowed as the mutable reference appears in the final value.
7777
```
7878

79+
> [!NOTE]
80+
> Constant initializers can be thought of, in most cases, as being inlined wherever the constant appears. If a constant whose value contains a mutable reference to a mutable static were to appear twice, and this were to be allowed, that would create two mutable references, each having `'static` lifetime, to the same place. This could quickly lead to undefined behavior.
81+
>
82+
> Constants that contain mutable references to temporaries whose scopes have been extended to the end of the program have that same problem and additional one.
83+
>
84+
> ```rust,compile_fail,E0764
85+
> const _: &mut u8 = &mut 0; // ERROR.
86+
> // ^^^^^^
87+
> // Not allowed as the mutable reference appears in the final value and
88+
> // because the constant expression contains a mutable borrow of an
89+
> // expression whose temporary scope would be extended to the end of
90+
> // the program.
91+
> ```
92+
>
93+
> Here, the value `0` is a temporary whose scope is extended to the end of the program (see [destructors.scope.lifetime-extension.static]). Such temporaries cannot be mutably borrowed in constant expressions (see [const-eval.const-expr.borrows]).
94+
>
95+
> To allow this, we'd have to decide whether each use of the constant creates a new `u8` value or whether each use shares the same lifetime-extended temporary. The latter choice, though closer to how `rustc` thinks about this today, would break the conceptual model that, in most cases, the constant initializer can be thought of as being inlined wherever the constant is used. Since we haven't decided, and due to the other problem mentioned, this is not allowed.
96+
7997
```rust,compile_fail,E0080
8098
# #![allow(static_mut_refs)]
8199
static mut S: u8 = 0;
@@ -158,6 +176,8 @@ const _: &&mut u8 = unsafe { &S }; // OK.
158176
> ```
159177
>
160178
> Here, the `AtomicU8` is a temporary whose scope is extended to the end of the program (see [destructors.scope.lifetime-extension.static]). Such temporaries with interior mutability cannot be borrowed in constant expressions (see [const-eval.const-expr.borrows]).
179+
>
180+
> To allow this, we'd have to decide whether each use of the constant creates a new `AtomicU8` or whether each use shares the same lifetime-extended temporary. The latter choice, though closer to how `rustc` thinks about this today, would break the conceptual model that, in most cases, the constant initializer can be thought of as being inlined wherever the constant is used. Since we haven't decided, this is not allowed.
161181
162182
r[items.const.expr-omission]
163183
The constant expression may only be omitted in a [trait definition].

0 commit comments

Comments
 (0)