Repository navigation
ReferencePropagation looks through field projections to find reborrow chains, but not when replacing #163777
Copy link
Copy link
Closed
Labels
A-mir-optArea: MIR optimizationsArea: MIR optimizationsC-bugCategory: This is a bug.Category: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeIssue: Correct Rust code lowers to incorrect machine codeP-highHigh priorityHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
When run with Miri this program runs fine, but when ReferencePropagation is enabled, it reports UB:
#![feature(custom_mir, core_intrinsics)]
#![allow(internal_features)]
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn maybe_dead_field_reborrow(m: bool) -> i32 {
use std::intrinsics::mir::*;
mir! {
let x: (i32, i32);
let r: &mut (i32, i32);
let r2: &mut i32;
{
StorageLive(x);
x = (0, 0);
r = &mut x;
(*r).0 = 1;
r2 = &mut (*r).0;
match m { true => bb1, _ => bb2 }
}
bb1 = {
StorageDead(x);
Goto(bb2)
}
bb2 = {
RET = *r2;
Return()
}
}
}
fn main() {
maybe_dead_field_reborrow(false);
}The transformation is:
fn maybe_dead_field_reborrow(_1: bool) -> i32 {
let mut _0: i32;
let mut _2: (i32, i32);
let mut _3: &mut (i32, i32);
let mut _4: &mut i32;
bb0: {
StorageLive(_2);
_2 = (const 0_i32, const 0_i32);
_3 = &mut _2;
- ((*_3).0: i32) = const 1_i32;
- _4 = &mut ((*_3).0: i32);
+ (_2.0: i32) = const 1_i32;
switchInt(copy _1) -> [1: bb1, otherwise: bb2];
}
bb1: {
StorageDead(_2);
goto -> bb2;
}
bb2: {
- _0 = copy (*_4);
+ _0 = copy ((*_3).0: i32);
return;
}
}This transformation is wrong because we create a reference to the field, then mutate the field directly, then try to read through the reference. The write invalidates the reference.
I'm not sure why I've never managed to provoke this with Rustlantis. I found this with an LLM, it's clearly inspired by this existing test case:
rust/tests/mir-opt/reference_prop.rs
Lines 735 to 778 in 260f1ac
| #[custom_mir(dialect = "runtime", phase = "post-cleanup")] | |
| fn maybe_dead(m: bool) { | |
| // CHECK-LABEL: fn maybe_dead( | |
| // CHECK: (*_5) = const 7_i32; | |
| use std::intrinsics::mir::*; | |
| mir! { | |
| let x: i32; | |
| let y: i32; | |
| { | |
| StorageLive(x); | |
| StorageLive(y); | |
| x = 5; | |
| y = 5; | |
| let a = &x; | |
| let b = &mut y; | |
| // As we don't replace `b` in `bb2`, we cannot replace it here either. | |
| *b = 7; | |
| // But this can still be replaced. | |
| let u = *a; | |
| match m { true => bb1, _ => bb2 } | |
| } | |
| bb1 = { | |
| StorageDead(x); | |
| StorageDead(y); | |
| Call(RET = opaque(u), ReturnTo(bb2), UnwindContinue()) | |
| } | |
| bb2 = { | |
| // As `x` may be `StorageDead`, `a` may be dangling, so we do nothing. | |
| let z = *a; | |
| Call(RET = opaque(z), ReturnTo(bb3), UnwindContinue()) | |
| } | |
| bb3 = { | |
| // As `y` may be `StorageDead`, `b` may be dangling, so we do nothing. | |
| // This implies that we also do not substitute `b` in `bb0`. | |
| let t = *b; | |
| Call(RET = opaque(t), ReturnTo(retblock), UnwindContinue()) | |
| } | |
| retblock = { | |
| Return() | |
| } | |
| } | |
| } | |
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-mir-optArea: MIR optimizationsArea: MIR optimizationsC-bugCategory: This is a bug.Category: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeIssue: Correct Rust code lowers to incorrect machine codeP-highHigh priorityHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Activity
saethlin commentedon Oct 5, 2026
This might be a duplicate of #132898 ?
rustbot commentedon Oct 5, 2026
Assigning P-high (discussion on Zulip).
Rollup merge of rust-lang#163778 - saethlin:refprop-indirect-places, …
Rollup merge of rust-lang#163778 - saethlin:refprop-indirect-places, …
Rollup merge of rust-lang#163778 - saethlin:refprop-indirect-places, …
Rollup merge of rust-lang#163778 - saethlin:refprop-indirect-places, …
Unrolled build for #163778 in rollup 163957
Rollup merge of #163778 - saethlin:refprop-indirect-places, r=dianqk