Skip to content

Commit 9308f3a

Browse files
authored
Merge pull request #10 from RalfJung/const-refs
More on references and promotion
2 parents ad195b5 + 53d6958 commit 9308f3a

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

const_refs.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
# References in constants
22

33
Constants of reference type are not an entirely straight-forward topic, for
4-
reasonings unrelated to [const safety](const_safety.md). The issue is that
4+
reasons unrelated to [const safety](const_safety.md). The issue is that
55
every use of a constant like
66
```rust
77
const REF: &u32 = &42;
88
```
99
is supposed to behave as if the value of the constant was copy-pasted into every
1010
place where it is used. However, the *real* behavior is that a single global
1111
"static" allocation is created containing the `42`, and every use of `REF` gets
12-
evaluated to the address of that static. There are three reasons why this could
13-
be an issue.
12+
evaluated to the address of that static. It's as if we had written
13+
```rust
14+
const REF: &u32 = { static _STATIC = 42; &_STATIC };
15+
```
16+
except that isn't allowed because constants cannot refer to statics.
17+
18+
There are three reasons why this could be an issue.
1419

1520
## Pointer equality
1621

@@ -39,7 +44,7 @@ is actually accepted by the compiler because we know that there is no
3944
Finally, the same constant reference is actually shared across threads. This is
4045
very similar to multiple threads having a shared reference to the same `static`,
4146
which is why `static` must be `Sync`. So it seems like we should reject
42-
non-`Sync` types.
47+
non-`Sync` types, conforming with the desugaring described above.
4348

4449
However, this does not currently happen, and there are several crates across the
4550
ecosystem that would break if we just started enforcing this now. See

promotion.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Const promotion
22

3+
"Promotion" is a mechanism that affects code like `&3`: Instead of putting it on
4+
the stack, the `3` is allocated in global static memory and a reference with
5+
lifetime `'static` is provided. This is essentially an automatic transformation
6+
turning `&EXPR` into `{ const _PROMOTED = &EXPR; EXPR }`, but only if `EXPR`
7+
qualifies.
8+
39
Note that promotion happens on the MIR, not on surface-level syntax. This is
410
relevant when discussing e.g. handling of panics caused by overflowing
511
arithmetic.
@@ -8,11 +14,12 @@ arithmetic.
814

915
### 1. Panics
1016

11-
Promotion is not allowed to throw away side effects. This includes
12-
panicking. Let us look at what happens when we promote `&(0_usize - 1)` in a
13-
debug build: We have to avoid erroring at compile-time (because that would be
14-
promotion breaking compilation), but we must be sure to error correctly at
15-
run-time. In the MIR, this looks roughly like
17+
Promotion is not allowed to throw away side effects. This includes panicking.
18+
Let us look at what happens when we promote `&(0_usize - 1)` in a debug build:
19+
We have to avoid erroring at compile-time, because that would be promotion
20+
breaking compilation (the code would have compiled just fine if we hadn't
21+
promoted), but we must be sure to error correctly at run-time. In the MIR, this
22+
looks roughly like
1623

1724
```
1825
_tmp1 = CheckedSub (const 0usize) (const 1usize)
@@ -23,10 +30,10 @@ _tmp2 = tmp1.0
2330
_res = &_tmp2
2431
```
2532

26-
Both `_tmp1` and `_tmp2` are promoted to statics. `_tmp1` evaluates to `(~0,
27-
true)`, so the assertion will always fail at run-time. Computing `_tmp2` fails
28-
with a panic, which is thrown away -- so we have no result. In principle, we
29-
could generate any code for this because we know the code is unreachable (the
33+
Both `_tmp1` and `_tmp2` are promoted. `_tmp1` evaluates to `(~0, true)`, so
34+
the assertion will always fail at run-time. Computing `_tmp2` fails with a
35+
panic, which is thrown away -- so we have no result. In principle, we could
36+
generate any code for this because we know the code is unreachable (the
3037
assertion is going to fail). Just to be safe, we generate a call to
3138
`llvm.trap`.
3239

@@ -91,6 +98,13 @@ TODO: Fill this with information.
9198
[Constant references](const_refs.md) impose some restrictions on the data they
9299
point to; the same restrictions apply to promoteds.
93100

101+
### 5. Accessing statics
102+
103+
Since the promoted code is evaluated at compile-time, we must make sure that it
104+
does not access any mutable statics (including safe `static` with interior
105+
mutability), not even read from them. Their value could have changed at
106+
run-time, so we wouldn't be producing the correct result.
107+
94108
## Open questions
95109

96110
* There is a fourth kind of CTFE failure -- and endless loop being detected.

0 commit comments

Comments
 (0)