|
| 1 | +# Constants in patterns |
| 2 | + |
| 3 | +Constants that pass the [structural equality check](https://github.com/rust-lang/rust/issues/74446) can be used in patterns: |
| 4 | +```rust |
| 5 | +const FOO: i32 = 13; |
| 6 | + |
| 7 | +fn is_foo(x: i32) -> bool { |
| 8 | + match x { |
| 9 | + FOO => true, |
| 10 | + _ => false, |
| 11 | + } |
| 12 | +} |
| 13 | +``` |
| 14 | +However, that check has some loopholes, so e.g. `&T` can be used in a pattern no matter the `T`. |
| 15 | + |
| 16 | +A const-pattern is compiled by calling `PartialEq::eq` to compare the subject of the `match` with the constant, |
| 17 | +except for TODO where the constant is treated as if it was inlined as a pattern (and the usual `match` tree is constructed). |
| 18 | + |
| 19 | +## Soundness concerns |
| 20 | + |
| 21 | +Most of the time there are no extra soundness concerns due to const-patterns; except for surprising behavior nothing can go wrong when the structural equality check gives a wrong answer. |
| 22 | +However, there is one exception: some constants participate in exhaustiveness checking. |
| 23 | +If a pattern is incorrectly considered exhaustive, that leads to a critical soundness bug. |
| 24 | + |
| 25 | +Exhaustiveness checking is done for constants of type TODO, as well as `&[u8]` and `&str` (but no other types with references). |
| 26 | +This means we can write: |
| 27 | +```rust |
| 28 | +#![feature(exclusive_range_pattern)] |
| 29 | +#![feature(half_open_range_patterns)] |
| 30 | +const PAT: &[u8] = &[0]; |
| 31 | + |
| 32 | +pub fn test(x: &[u8]) -> bool { |
| 33 | + match x { |
| 34 | + PAT => true, |
| 35 | + &[] => false, |
| 36 | + &[1..] => false, |
| 37 | + &[_, _, ..] => false |
| 38 | + } |
| 39 | +} |
| 40 | +``` |
| 41 | + |
| 42 | +To ensure soundness of exhaustiveness checking, it is crucial that all data considered this check is fully immutable. |
| 43 | +In particular, for constants of reference type, it is important that they only point to immutable data. |
| 44 | +For this reason, the static const checks reject references to `static` items. |
| 45 | +This is a new soundness concern that otherwise does not come up during CTFE (where *reading from* a mutable `static` during const initialization is a problem, but just referencing a mutable `static` is not). |
| 46 | +A more precise check could be possible, but is non-trivial: even an immutable `static` could point to a mutable `static`; that would have to be excluded. |
| 47 | +(We could, in principle, also rely on it being UB to have a shared reference to mutable memory, but for now we prefer not to rely on the aliasing model like that---aliasing of global pointers is a tricky subject.) |
| 48 | + |
| 49 | +*Dynamic check.* |
| 50 | +To dynamically ensure constants only point to read-only data, we maintain a global invariant: |
| 51 | +pointers to a `static` (including memory that was created as part of interning a `static`) may never "leak" to a non-`static`. |
| 52 | +All memory outside of `static`s is marked as immutable. |
| 53 | +As a consequence, non-`static`s recursively only point to immutable memory. |
| 54 | + |
| 55 | +This check is uncomfortably close to the static checks, and fragile due to its reliance on a global invariant. |
| 56 | +Longer-term, it would be better to move to a more local check, by making validation check if consts are recursively read-only. |
| 57 | +This check (unlike our current validation) would have to descend through pointers to `static`. |
| 58 | + |
| 59 | +An alternative could be to wait for the [value tree proposal](https://github.com/rust-lang/compiler-team/issues/323) to be implemented. |
| 60 | +Then we could check during value tree construction that all memory is read-only (if we use the CTFE machine in `const`-mode, that will happen implicitly), and thus we know for sure we can rely on the value tree to be sound to use for exhaustiveness checking. |
| 61 | +How exactly this looks like depends on how we resolve [pattern matching allowing many things that do not fit a value tree](https://github.com/rust-lang/rust/issues/74446#issuecomment-663439899). |
| 62 | +However, if only the well-behaved part of the value tree is used for exhaustiveness checking, handling these extra patterns should not interact closely with the soundness concerns discussed here. |
0 commit comments