diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-10-06 11:06:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-06 11:06:57 +0200 |
| commit | 9aaebd481a63df4673691dfd35f9a7eda5c51724 (patch) | |
| tree | dfaafcfcfc9b8e1f1bc95d48394bfca2cec64097 /compiler/rustc_mir_transform/src/coverage/counters.rs | |
| parent | 7d53688b25d52d822c7094ee80db42b2b2f2a8d3 (diff) | |
| parent | e8d5eb2a2b6cdddd6725501e1b54a33c278d9697 (diff) | |
| download | rust-9aaebd481a63df4673691dfd35f9a7eda5c51724.tar.gz rust-9aaebd481a63df4673691dfd35f9a7eda5c51724.zip | |
Rollup merge of #129392 - compiler-errors:raw-ref-op-doesnt-diverge-but-more, r=lcnr
Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too
Fixes #117288.
This PR implements a heuristic which disables two things that are currently being performed on the HIR when we have **expressions that involve place-like expressions that point to `!`**. Specifically, it will (in certain cases explained below):
### (1.) Disable the `NeverToAny` coercion we implicitly insert for `!`.
Which fixes this inadvertent, sneaky unsoundness:
```
unsafe {
let x: *const ! = &0 as *const u8 as *const !;
let _: () = *x;
}
```
which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.
### (2.) Disable the logic which considers expression which evaluate to `!` to diverge, which affects the type returned by the containing block.
Which fixes this unsoundness:
```
fn make_up_a_value<T>() -> T {
unsafe {
let x: *const ! = &0 as *const u8 as *const !;
let _ = *x;
}
}
```
We disable these two operations **if** the expression is a place-like expression (locals, statics, field projections, index operations, and deref operations), and if the parent expression is either:
(1.) the LHS of an assignment
(2.) AddrOf
(3.) A match or let **unless** all of the *patterns consitute a read*, which is explained below:
And finally, a pattern currently is considered to constitute a read **unless** it is a wildcard, or an OR pattern. An OR pattern is considered to constitute a read if all of its subpatterns constitute a read, to remain as conservative as possible in cases like `_ | subpat` or `subpat | _`.
All other patterns are considered currently to constitute a read. Specifically, because `NeverToAny` is a coercion performed on a *value* and not a *place*, `Struct { .. }` on a `!` type must be a coercion currently, and we currently rely on this behavior to allow us to perform coercions like `let _: i32 = x;` where `x: !`.
This is already considered UB by [miri](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=daf3a2246433fe43fdc07d1389c276c9), but also means it does not affect the preexisting UB in this case:
```
let Struct { .. } = *never_ptr;
```
Even though it's likely up for debate since we're not actually reading any data out of the struct, it almost certainly causes inference changes which I do *NOT* want to fix in this PR.
Diffstat (limited to 'compiler/rustc_mir_transform/src/coverage/counters.rs')
0 files changed, 0 insertions, 0 deletions
