Skip to content

ReferencePropagation looks through field projections to find reborrow chains, but not when replacing #163777

Description

@saethlin

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:

#[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()
}
}
}

Activity

  1. self-assigned this
    on Oct 5, 2026
  2. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    C-bugCategory: This is a bug.
    A-mir-optArea: MIR optimizations
    I-miscompileIssue: Correct Rust code lowers to incorrect machine code
    on Oct 5, 2026
  3. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Oct 5, 2026
  4. saethlin commented on Oct 5, 2026

    @saethlin
    MemberAuthor

    This might be a duplicate of #132898 ?

  5. removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Oct 5, 2026
  6. rustbot commented on Oct 5, 2026

    @rustbot
    Collaborator

    Assigning P-high (discussion on Zulip).

  7. removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Oct 5, 2026
  8. added 4 commits that reference this issue on Oct 6, 2026
  9. added a commit that references this issue on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-mir-optArea: MIR optimizationsC-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeP-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions