|
| 1 | +# References in constants |
| 2 | + |
| 3 | +Constants of reference type are not an entirely straight-forward topic, for |
| 4 | +reasonins unrelated to [const safety](const_safety.md). The issue is that |
| 5 | +every use of a constant like |
| 6 | +```rust |
| 7 | +const REF: &u32 = &42; |
| 8 | +``` |
| 9 | +is supposed to behave as if the value of the constant was copy-pasted into every |
| 10 | +place where it is used. However, the *real* behavior is that a single global |
| 11 | +"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. |
| 14 | + |
| 15 | +## Pointer equality |
| 16 | + |
| 17 | +We effectively "deduplicate" all the `42` that would otherwise locally be |
| 18 | +created at each use site of `REF`. This is observable when the programs |
| 19 | +compares these pointers for equality. We consider this okay, i.e., programs may |
| 20 | +not rely on such constants all getting distinct addresses. They may not rely on |
| 21 | +them all getting the same address either. |
| 22 | + |
| 23 | +## Interior mutability |
| 24 | + |
| 25 | +If the reference has type `&Cell<i32>` it is quite clear that the program can |
| 26 | +easily observe whether two references point to the same memory even without |
| 27 | +comparing their address: Changes through one reference will affect reads through |
| 28 | +the other. So, we cannot allow constant references to types that have interior |
| 29 | +mutability (types that are not `Freeze`). |
| 30 | + |
| 31 | +However, we can do better than that: Even if a *type* is not `Freeze`, it can |
| 32 | +have *values* that do not exhibit any interior mutability. For example, `&None` |
| 33 | +at type `&Option<Cell<i32>>` would be rejected by the naive analysis above, but |
| 34 | +is actually accepted by the compiler because we know that there is no |
| 35 | +`UnsafeCell` here that would permit interior mutability. |
| 36 | + |
| 37 | +## `Sync` |
| 38 | + |
| 39 | +Finally, the same constant reference is actually shared across threads. This is |
| 40 | +very similar to multiple threads having a shared reference to the same `static`, |
| 41 | +which is why `static` must be `Sync`. So it seems like we should reject |
| 42 | +non-`Sync` types. |
| 43 | + |
| 44 | +However, this does not currently happen, and there are several crates across the |
| 45 | +ecosystem that would break if we just started enforcing this now. See |
| 46 | +[this issue](https://github.com/rust-lang/rust/issues/49206) and the |
| 47 | +[PR attempting to fix this](https://github.com/rust-lang/rust/pull/54424/). |
0 commit comments