// unit-test: ReferencePropagation // needs-unwind #![feature(raw_ref_op)] #![feature(core_intrinsics, custom_mir)] #[inline(never)] fn opaque(_: impl Sized) {} fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { // CHECK-LABEL: fn reference_propagation( // Propagation through a reference. { // CHECK: bb0: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[c:_.*]] = [[a]]; let a = 5_usize; let b = &a; // This borrow is only used once. let c = *b; // This should be optimized. opaque(()); // We use opaque to separate cases into basic blocks in the MIR. } // Propagation through two references. { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[btmp:_.*]] = &[[a2]]; // CHECK: [[b]] = move [[btmp]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let a2 = 7_usize; let mut b = &a; b = &a2; // `b` is assigned twice, so we cannot propagate it. let c = *b; opaque(()); } // Propagation through a borrowed reference. { // CHECK: bb2: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[d:_.*]] = &[[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let b = &a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but do not propagate it opaque(d); // prevent `d` from being removed. } // Propagation through a mutably borrowed reference. { // CHECK: bb3: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[d:_.*]] = &raw mut [[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let mut b = &a; let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. { // CHECK: bb4: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[c:_.*]] = [[a]]; let a = 7_usize; let b = &a; let c = *b; opaque(b); // `b` escapes here, but we can still replace immutable borrow } // Propagation through a transitively escaping borrow. { // CHECK: bb5: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b1:_.*]] = &[[a]]; // CHECK: [[c:_.*]] = [[a]]; // CHECK: [[b2:_.*]] = [[b1]]; // CHECK: [[c2:_.*]] = [[a]]; // CHECK: [[b3:_.*]] = [[b2]]; let a = 7_usize; let b1 = &a; let c = *b1; let b2 = b1; let c2 = *b2; let b3 = b2; // `b3` escapes here, so we can only replace immutable borrow, // for either `b`, `b2` or `b3`. opaque(b3); } // Propagation a reborrow of an argument. { // CHECK: bb6: { // CHECK-NOT: {{_.*}} = &(*_1); // CHECK: [[b:_.*]] = (*_1); let a = &*single; let b = *a; // This should be optimized as `*single`. opaque(()); } // Propagation a reborrow of a mutated argument. { // CHECK: bb7: { // CHECK: [[a:_.*]] = &(*_2); // CHECK: [[tmp:_.*]] = &(*_1); // CHECK: _2 = move [[tmp]]; // CHECK: [[b:_.*]] = (*[[a]]); let a = &*multiple; multiple = &*single; let b = *a; // This should not be optimized. opaque(()); } // Fixed-point propagation through a borrowed reference. { // CHECK: bb8: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[d:_.*]] = &[[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let b = &a; let d = &b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } // Fixed-point propagation through a mutably borrowed reference. { // CHECK: bb9: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[d:_.*]] = &mut [[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let mut b = &a; let d = &mut b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } } fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a mut T) { // CHECK-LABEL: fn reference_propagation_mut( // Propagation through a reference. { // CHECK: bb0: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[c:_.*]] = [[a]]; let mut a = 5_usize; let b = &mut a; // This borrow is only used once. let c = *b; // This should be optimized. opaque(()); } // Propagation through two references. { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[btmp:_.*]] = &mut [[a2]]; // CHECK: [[b]] = move [[btmp]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut a2 = 7_usize; let mut b = &mut a; b = &mut a2; // `b` is assigned twice, so we cannot propagate it. let c = *b; opaque(()); } // Propagation through a borrowed reference. { // CHECK: bb2: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let b = &mut a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. opaque(d); // prevent `d` from being removed. } // Propagation through a mutably borrowed reference. { // CHECK: bb3: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[d:_.*]] = &raw mut [[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut b = &mut a; let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. { // CHECK: bb4: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 7_usize; let b = &mut a; let c = *b; opaque(b); // `b` escapes here, so we can only replace immutable borrow } // Propagation through a transitively escaping borrow. { // CHECK: bb5: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b1:_.*]] = &mut [[a]]; // CHECK: [[c:_.*]] = (*[[b1]]); // CHECK: [[b2:_.*]] = move [[b1]]; // CHECK: [[c2:_.*]] = (*[[b2]]); // CHECK: [[b3:_.*]] = move [[b2]]; let mut a = 7_usize; let b1 = &mut a; let c = *b1; let b2 = b1; let c2 = *b2; let b3 = b2; // `b3` escapes here, so we can only replace immutable borrow, // for either `b`, `b2` or `b3`. opaque(b3); } // Propagation a reborrow of an argument. { // CHECK: bb6: { // CHECK-NOT: {{_.*}} = &(*_1); // CHECK: [[b:_.*]] = (*_1); let a = &mut *single; let b = *a; // This should be optimized as `*single`. opaque(()); } // Propagation a reborrow of a mutated argument. { // CHECK: bb7: { // CHECK: [[a:_.*]] = &mut (*_2); // CHECK: [[tmp:_.*]] = &mut (*_1); // CHECK: _2 = move [[tmp]]; // CHECK: [[b:_.*]] = (*[[a]]); let a = &mut *multiple; multiple = &mut *single; let b = *a; // This should not be optimized. opaque(()); } // Fixed-point propagation through a borrowed reference. { // CHECK: bb8: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let b = &mut a; let d = &b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } // Fixed-point propagation through a mutably borrowed reference. { // CHECK: bb9: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[d:_.*]] = &mut [[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut b = &mut a; let d = &mut b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } } fn reference_propagation_const_ptr(single: *const T, mut multiple: *const T) { // CHECK-LABEL: fn reference_propagation_const_ptr( // Propagation through a reference. unsafe { // CHECK: bb0: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[c:_.*]] = [[a]]; let a = 5_usize; let b = &raw const a; // This borrow is only used once. let c = *b; // This should be optimized. opaque(()); } // Propagation through two references. unsafe { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[btmp:_.*]] = &raw const [[a2]]; // CHECK: [[b]] = move [[btmp]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let a2 = 7_usize; let mut b = &raw const a; b = &raw const a2; // `b` is assigned twice, so we cannot propagate it. let c = *b; opaque(()); } // Propagation through a borrowed reference. unsafe { // CHECK: bb2: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let b = &raw const a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. opaque(d); // prevent `d` from being removed. } // Propagation through a mutably borrowed reference. unsafe { // CHECK: bb3: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[d:_.*]] = &raw mut [[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let mut b = &raw const a; let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. unsafe { // CHECK: bb4: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[c:_.*]] = [[a]]; let a = 7_usize; let b = &raw const a; let c = *b; opaque(b); // `b` escapes here, so we can only replace immutable borrow } // Propagation through a transitively escaping borrow. unsafe { // CHECK: bb5: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b1:_.*]] = &raw const [[a]]; // CHECK: [[c:_.*]] = [[a]]; // CHECK: [[b2:_.*]] = [[b1]]; // CHECK: [[c2:_.*]] = [[a]]; // CHECK: [[b3:_.*]] = [[b2]]; let a = 7_usize; let b1 = &raw const a; let c = *b1; let b2 = b1; let c2 = *b2; let b3 = b2; // `b3` escapes here, so we can only replace immutable borrow, // for either `b`, `b2` or `b3`. opaque(b3); } // Propagation a reborrow of an argument. unsafe { // CHECK: bb6: { // CHECK-NOT: {{_.*}} = &(*_1); // CHECK: [[b:_.*]] = (*_1); let a = &raw const *single; let b = *a; // This should be optimized as `*single`. opaque(()); } // Propagation a reborrow of a mutated argument. unsafe { // CHECK: bb7: { // CHECK: [[a:_.*]] = &raw const (*_2); // CHECK: [[tmp:_.*]] = &raw const (*_1); // CHECK: _2 = move [[tmp]]; // CHECK: [[b:_.*]] = (*[[a]]); let a = &raw const *multiple; multiple = &raw const *single; let b = *a; // This should not be optimized. opaque(()); } // Propagation through a reborrow. unsafe { // CHECK: bb8: { // CHECK: [[a:_.*]] = const 13_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[d:_.*]] = &raw const [[a]]; // CHECK: [[c:_.*]] = [[a]]; let a = 13_usize; let b = &raw const a; let c = &raw const *b; let e = *c; opaque(()); } // Fixed-point propagation through a borrowed reference. unsafe { // CHECK: bb9: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let b = &raw const a; let d = &b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } // Fixed-point propagation through a borrowed reference. unsafe { // CHECK: bb10: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[d:_.*]] = &mut [[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let a = 5_usize; let mut b = &raw const a; let d = &mut b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } } fn reference_propagation_mut_ptr(single: *mut T, mut multiple: *mut T) { // CHECK-LABEL: fn reference_propagation_mut_ptr( // Propagation through a reference. unsafe { // CHECK: bb0: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[c:_.*]] = [[a]]; let mut a = 5_usize; let b = &raw mut a; // This borrow is only used once. let c = *b; // This should be optimized. opaque(()); } // Propagation through two references. unsafe { // CHECK: bb1: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[btmp:_.*]] = &raw mut [[a2]]; // CHECK: [[b]] = move [[btmp]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut a2 = 7_usize; let mut b = &raw mut a; b = &raw mut a2; // `b` is assigned twice, so we cannot propagate it. let c = *b; opaque(()); } // Propagation through a borrowed reference. unsafe { // CHECK: bb2: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let b = &raw mut a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. opaque(d); // prevent `d` from being removed. } // Propagation through a mutably borrowed reference. unsafe { // CHECK: bb3: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[d:_.*]] = &raw mut [[b]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut b = &raw mut a; let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. unsafe { // CHECK: bb4: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 7_usize; let b = &raw mut a; let c = *b; opaque(b); // `b` escapes here, so we can only replace immutable borrow } // Propagation through a transitively escaping borrow. unsafe { // CHECK: bb5: { // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b1:_.*]] = &raw mut [[a]]; // CHECK: [[c:_.*]] = (*[[b1]]); // CHECK: [[b2:_.*]] = [[b1]]; // CHECK: [[c2:_.*]] = (*[[b2]]); // CHECK: [[b3:_.*]] = [[b2]]; let mut a = 7_usize; let b1 = &raw mut a; let c = *b1; let b2 = b1; let c2 = *b2; let b3 = b2; // `b3` escapes here, so we can only replace immutable borrow, // for either `b`, `b2` or `b3`. opaque(b3); } // Propagation a reborrow of an argument. unsafe { // CHECK: bb6: { // CHECK-NOT: {{_.*}} = &(*_1); // CHECK: [[b:_.*]] = (*_1); let a = &raw mut *single; let b = *a; // This should be optimized as `*single`. opaque(()); } // Propagation a reborrow of a mutated argument. unsafe { // CHECK: bb7: { // CHECK: [[a:_.*]] = &raw mut (*_2); // CHECK: [[tmp:_.*]] = &raw mut (*_1); // CHECK: _2 = move [[tmp]]; // CHECK: [[b:_.*]] = (*[[a]]); let a = &raw mut *multiple; multiple = &raw mut *single; let b = *a; // This should not be optimized. opaque(()); } // Fixed-point propagation through a borrowed reference. unsafe { // CHECK: bb8: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[d:_.*]] = &[[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let b = &raw mut a; let d = &b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } // Fixed-point propagation through a mutably borrowed reference. unsafe { // CHECK: bb9: { // CHECK: [[a:_.*]] = const 5_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[d:_.*]] = &mut [[b]]; // FIXME this could be [[a]] // CHECK: [[c:_.*]] = (*[[b]]); let mut a = 5_usize; let mut b = &raw mut a; let d = &mut b; // first round promotes debuginfo for `d` let c = *b; // second round propagates this dereference opaque(()); } } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn read_through_raw(x: &mut usize) -> usize { // CHECK-LABEL: read_through_raw // CHECK: bb0: { // CHECK-NEXT: _0 = (*_1); // CHECK-NEXT: _0 = (*_1); // CHECK-NEXT: return; use std::intrinsics::mir::*; mir!( let r1: &mut usize; let r2: &mut usize; let p1: *mut usize; let p2: *mut usize; { r1 = &mut *x; r2 = &mut *r1; p1 = &raw mut *r1; p2 = &raw mut *r2; RET = *p1; RET = *p2; Return() } ) } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn multiple_storage() { // CHECK-LABEL: multiple_storage // CHECK: _3 = (*_2); use std::intrinsics::mir::*; mir!( let x: i32; { StorageLive(x); x = 5; let z = &x; StorageDead(x); StorageLive(x); // As there are multiple `StorageLive` statements for `x`, we cannot know if this `z`'s // pointer address is the address of `x`, so do nothing. let y = *z; Call(RET = opaque(y), retblock) } retblock = { Return() } ) } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn dominate_storage() { // CHECK-LABEL: dominate_storage // CHECK: _5 = (*_2); use std::intrinsics::mir::*; mir!( let x: i32; let r: &i32; let c: i32; let d: bool; { Goto(bb0) } bb0 = { x = 5; r = &x; Goto(bb1) } bb1 = { let c = *r; Call(RET = opaque(c), bb2) } bb2 = { StorageDead(x); StorageLive(x); let d = true; match d { false => bb2, _ => bb0 } } ) } #[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), bb2) } bb2 = { // As `x` may be `StorageDead`, `a` may be dangling, so we do nothing. let z = *a; Call(RET = opaque(z), bb3) } 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), retblock) } retblock = { Return() } ) } fn mut_raw_then_mut_shr() -> (i32, i32) { // CHECK-LABEL: fn mut_raw_then_mut_shr( // CHECK-NOT: (*{{_.*}}) let mut x = 2; let xref = &mut x; let xraw = &mut *xref as *mut _; let xshr = &*xref; // Verify that we completely replace with `x` in both cases. let a = *xshr; unsafe { *xraw = 4; } (a, x) } fn unique_with_copies() { // CHECK-LABEL: fn unique_with_copies( // CHECK: [[a:_.*]] = const 0_i32; // CHECK: [[x:_.*]] = &raw mut [[a]]; // CHECK-NOT: [[a]] // CHECK: [[tmp:_.*]] = (*[[x]]); // CHECK-NEXT: opaque::(move [[tmp]]) // CHECK-NOT: [[a]] // CHECK: StorageDead([[a]]); // CHECK-NOT: [[a]] // CHECK: [[tmp:_.*]] = (*[[x]]); // CHECK-NEXT: opaque::(move [[tmp]]) let y = { let mut a = 0; let x = &raw mut a; // `*y` is not replacable below, so we must not replace `*x`. unsafe { opaque(*x) }; x }; // But rewriting as `*x` is ok. unsafe { opaque(*y) }; } fn debuginfo() { // CHECK-LABEL: fn debuginfo( // FIXME: This features waits for DWARF implicit pointers in LLVM. // CHECK: debug ref_mut_u8 => _{{.*}}; // CHECK: debug field => _{{.*}}; // CHECK: debug reborrow => _{{.*}}; // CHECK: debug variant_field => _{{.*}}; // CHECK: debug constant_index => _{{.*}}; // CHECK: debug subslice => _{{.*}}; // CHECK: debug constant_index_from_end => _{{.*}}; // CHECK: debug multiple_borrow => _{{.*}}; struct T(u8); let ref_mut_u8 = &mut 5_u8; let field = &T(0).0; // Verify that we don't emit `&*` in debuginfo. let reborrow = &*ref_mut_u8; match Some(0) { None => {} Some(ref variant_field) => {} } // `constant_index_from_end` and `subslice` should not be promoted, as their value depends // on the slice length. if let [_, ref constant_index, subslice @ .., ref constant_index_from_end] = &[6; 10][..] { } let multiple_borrow = &&&mut T(6).0; } fn many_debuginfo() { // CHECK-LABEL: fn many_debuginfo( // FIXME: This features waits for DWARF implicit pointers in LLVM. // CHECK: debug many_borrow => _{{.*}}; let a = 0; // Verify that we do not ICE on deeply nested borrows. let many_borrow = &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&a; } fn main() { let mut x = 5_usize; let mut y = 7_usize; reference_propagation(&x, &y); reference_propagation_mut(&mut x, &mut y); reference_propagation_const_ptr(&raw const x, &raw const y); reference_propagation_mut_ptr(&raw mut x, &raw mut y); read_through_raw(&mut x); multiple_storage(); dominate_storage(); maybe_dead(true); mut_raw_then_mut_shr(); unique_with_copies(); debuginfo(); many_debuginfo(); } // EMIT_MIR reference_prop.reference_propagation.ReferencePropagation.diff // EMIT_MIR reference_prop.reference_propagation_mut.ReferencePropagation.diff // EMIT_MIR reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff // EMIT_MIR reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff // EMIT_MIR reference_prop.read_through_raw.ReferencePropagation.diff // EMIT_MIR reference_prop.multiple_storage.ReferencePropagation.diff // EMIT_MIR reference_prop.dominate_storage.ReferencePropagation.diff // EMIT_MIR reference_prop.maybe_dead.ReferencePropagation.diff // EMIT_MIR reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff // EMIT_MIR reference_prop.unique_with_copies.ReferencePropagation.diff // EMIT_MIR reference_prop.debuginfo.ReferencePropagation.diff