Skip to content

Commit b171088

Browse files
authored
Unrolled build for #147525
Rollup merge of #147525 - dianqk:ref_prop_debuginfo, r=cjgillot Replace locals in debuginfo records during ref_prop and dest_prop Fixes #147485. r? cjgillot
2 parents b3f8586 + 1ee2c58 commit b171088

File tree

10 files changed

+245
-14
lines changed

10 files changed

+245
-14
lines changed

compiler/rustc_middle/src/mir/visit.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,10 @@ macro_rules! super_body {
10981098
}
10991099
}
11001100

1101+
for var_debug_info in &$($mutability)? $body.var_debug_info {
1102+
$self.visit_var_debug_info(var_debug_info);
1103+
}
1104+
11011105
for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
11021106
$self.visit_basic_block_data(bb, data);
11031107
}
@@ -1127,10 +1131,6 @@ macro_rules! super_body {
11271131
);
11281132
}
11291133

1130-
for var_debug_info in &$($mutability)? $body.var_debug_info {
1131-
$self.visit_var_debug_info(var_debug_info);
1132-
}
1133-
11341134
$self.visit_span($(& $mutability)? $body.span);
11351135

11361136
if let Some(required_consts) = &$($mutability)? $body.required_consts {

compiler/rustc_mir_transform/src/dest_prop.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
277277
if self.merged_locals.contains(*local) =>
278278
{
279279
statement.make_nop(true);
280-
return;
281280
}
282281
_ => (),
283282
};

compiler/rustc_mir_transform/src/ref_prop.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ fn compute_replacement<'tcx>(
302302
return Replacer {
303303
tcx,
304304
targets: finder.targets,
305+
remap_var_debug_infos: IndexVec::from_elem(None, body.local_decls()),
305306
storage_to_remove,
306307
allowed_replacements,
307308
any_replacement: false,
@@ -381,6 +382,7 @@ fn fully_replaceable_locals(ssa: &SsaLocals) -> DenseBitSet<Local> {
381382
struct Replacer<'tcx> {
382383
tcx: TyCtxt<'tcx>,
383384
targets: IndexVec<Local, Value<'tcx>>,
385+
remap_var_debug_infos: IndexVec<Local, Option<Local>>,
384386
storage_to_remove: DenseBitSet<Local>,
385387
allowed_replacements: FxHashSet<(Local, Location)>,
386388
any_replacement: bool,
@@ -392,21 +394,45 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
392394
}
393395

394396
fn visit_var_debug_info(&mut self, debuginfo: &mut VarDebugInfo<'tcx>) {
395-
// If the debuginfo is a pointer to another place
396-
// and it's a reborrow: see through it
397-
while let VarDebugInfoContents::Place(ref mut place) = debuginfo.value
397+
if let VarDebugInfoContents::Place(ref mut place) = debuginfo.value
398398
&& place.projection.is_empty()
399-
&& let Value::Pointer(target, _) = self.targets[place.local]
400-
&& let &[PlaceElem::Deref] = &target.projection[..]
401399
{
402-
*place = Place::from(target.local);
403-
self.any_replacement = true;
400+
let mut new_local = place.local;
401+
402+
// If the debuginfo is a pointer to another place
403+
// and it's a reborrow: see through it
404+
while let Value::Pointer(target, _) = self.targets[new_local]
405+
&& let &[PlaceElem::Deref] = &target.projection[..]
406+
{
407+
new_local = target.local;
408+
}
409+
if place.local != new_local {
410+
self.remap_var_debug_infos[place.local] = Some(new_local);
411+
place.local = new_local;
412+
413+
self.any_replacement = true;
414+
}
404415
}
405416

406417
// Simplify eventual projections left inside `debuginfo`.
407418
self.super_var_debug_info(debuginfo);
408419
}
409420

421+
fn visit_statement_debuginfo(
422+
&mut self,
423+
stmt_debuginfo: &mut StmtDebugInfo<'tcx>,
424+
location: Location,
425+
) {
426+
let local = match stmt_debuginfo {
427+
StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => local,
428+
};
429+
if let Some(target) = self.remap_var_debug_infos[*local] {
430+
*local = target;
431+
self.any_replacement = true;
432+
}
433+
self.super_statement_debuginfo(stmt_debuginfo, location);
434+
}
435+
410436
fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
411437
loop {
412438
let Some((&PlaceElem::Deref, rest)) = place.projection.split_first() else { return };
@@ -437,8 +463,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
437463
{
438464
stmt.make_nop(true);
439465
}
440-
// Do not remove assignments as they may still be useful for debuginfo.
441-
_ => self.super_statement(stmt, loc),
466+
_ => {}
442467
}
468+
// Do not remove assignments as they may still be useful for debuginfo.
469+
self.super_statement(stmt, loc);
443470
}
444471
}

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_middle::ty::{
1717
self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Upcast, Variance,
1818
};
1919
use rustc_middle::{bug, span_bug};
20+
use rustc_mir_dataflow::debuginfo::debuginfo_locals;
2021
use rustc_trait_selection::traits::ObligationCtxt;
2122

2223
use crate::util::{self, is_within_packed};
@@ -80,6 +81,11 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
8081
cfg_checker.fail(location, msg);
8182
}
8283

84+
// Ensure that debuginfo records are not emitted for locals that are not in debuginfo.
85+
for (location, msg) in validate_debuginfos(body) {
86+
cfg_checker.fail(location, msg);
87+
}
88+
8389
if let MirPhase::Runtime(_) = body.phase
8490
&& let ty::InstanceKind::Item(_) = body.source.instance
8591
&& body.has_free_regions()
@@ -1595,3 +1601,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15951601
self.super_terminator(terminator, location);
15961602
}
15971603
}
1604+
1605+
pub(super) fn validate_debuginfos<'tcx>(body: &Body<'tcx>) -> Vec<(Location, String)> {
1606+
let mut debuginfo_checker =
1607+
DebuginfoChecker { debuginfo_locals: debuginfo_locals(body), failures: Vec::new() };
1608+
debuginfo_checker.visit_body(body);
1609+
debuginfo_checker.failures
1610+
}
1611+
1612+
struct DebuginfoChecker {
1613+
debuginfo_locals: DenseBitSet<Local>,
1614+
failures: Vec<(Location, String)>,
1615+
}
1616+
1617+
impl<'tcx> Visitor<'tcx> for DebuginfoChecker {
1618+
fn visit_statement_debuginfo(
1619+
&mut self,
1620+
stmt_debuginfo: &StmtDebugInfo<'tcx>,
1621+
location: Location,
1622+
) {
1623+
let local = match stmt_debuginfo {
1624+
StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => *local,
1625+
};
1626+
if !self.debuginfo_locals.contains(local) {
1627+
self.failures.push((location, format!("{local:?} is not in debuginfo")));
1628+
}
1629+
}
1630+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
- // MIR for `remap_debuginfo_locals` before DestinationPropagation
2+
+ // MIR for `remap_debuginfo_locals` after DestinationPropagation
3+
4+
fn remap_debuginfo_locals(_1: bool, _2: &bool) -> &bool {
5+
- debug c => _3;
6+
+ debug c => _2;
7+
let mut _0: &bool;
8+
let mut _3: &bool;
9+
let mut _4: bool;
10+
11+
bb0: {
12+
- // DBG: _3 = &_1;
13+
- StorageLive(_4);
14+
- _4 = copy _1;
15+
- _3 = copy _2;
16+
- switchInt(copy _4) -> [1: bb1, otherwise: bb2];
17+
+ // DBG: _2 = &_1;
18+
+ nop;
19+
+ nop;
20+
+ nop;
21+
+ switchInt(copy _1) -> [1: bb1, otherwise: bb2];
22+
}
23+
24+
bb1: {
25+
goto -> bb2;
26+
}
27+
28+
bb2: {
29+
- StorageDead(_4);
30+
- _0 = copy _3;
31+
+ nop;
32+
+ _0 = copy _2;
33+
return;
34+
}
35+
}
36+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//@ test-mir-pass: DestinationPropagation
2+
//@ compile-flags: -g -Zmir-enable-passes=+DeadStoreElimination-initial
3+
4+
#![feature(core_intrinsics, custom_mir)]
5+
#![crate_type = "lib"]
6+
7+
use std::intrinsics::mir::*;
8+
9+
// EMIT_MIR dest_prop.remap_debuginfo_locals.DestinationPropagation.diff
10+
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
11+
pub fn remap_debuginfo_locals(a: bool, b: &bool) -> &bool {
12+
// CHECK-LABEL: fn remap_debuginfo_locals(
13+
// CHECK: debug c => [[c:_.*]];
14+
// CHECK: bb0:
15+
// CHECK-NEXT: DBG: [[c]] = &_1;
16+
mir! {
17+
let _3: &bool;
18+
let _4: bool;
19+
debug c => _3;
20+
{
21+
_3 = &a;
22+
StorageLive(_4);
23+
_4 = a;
24+
_3 = b;
25+
match _4 {
26+
true => bb1,
27+
_ => bb2,
28+
}
29+
}
30+
bb1 = {
31+
Goto(bb2)
32+
}
33+
bb2 = {
34+
StorageDead(_4);
35+
RET = _3;
36+
Return()
37+
}
38+
}
39+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
- // MIR for `remap_debuginfo_locals` before ReferencePropagation
2+
+ // MIR for `remap_debuginfo_locals` after ReferencePropagation
3+
4+
fn remap_debuginfo_locals() -> () {
5+
let mut _0: ();
6+
let _1: &usize;
7+
let mut _2: *const usize;
8+
let _3: &usize;
9+
let _4: usize;
10+
let mut _5: &usize;
11+
scope 1 (inlined foo) {
12+
- debug a => _1;
13+
+ debug a => _5;
14+
}
15+
16+
bb0: {
17+
- StorageLive(_1);
18+
- StorageLive(_2);
19+
- StorageLive(_3);
20+
_5 = const remap_debuginfo_locals::promoted[0];
21+
- _3 = &(*_5);
22+
- _2 = &raw const (*_3);
23+
- // DBG: _1 = &(*_2);
24+
- _1 = &(*_2);
25+
- StorageDead(_2);
26+
- StorageDead(_3);
27+
- StorageDead(_1);
28+
+ // DBG: _5 = &(*_5);
29+
_0 = const ();
30+
return;
31+
}
32+
}
33+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ test-mir-pass: ReferencePropagation
2+
//@ compile-flags: -g -Zub_checks=false -Zinline-mir -Zmir-enable-passes=+DeadStoreElimination-initial
3+
4+
#![feature(core_intrinsics, custom_mir)]
5+
#![crate_type = "lib"]
6+
7+
use std::intrinsics::mir::*;
8+
9+
// EMIT_MIR ref_prop.remap_debuginfo_locals.ReferencePropagation.diff
10+
pub fn remap_debuginfo_locals() {
11+
// CHECK-LABEL: fn remap_debuginfo_locals()
12+
// CHECK: debug a => [[a:_.*]];
13+
// CHECK: bb0:
14+
// CHECK-NEXT: [[a]] = const
15+
// CHECK-NEXT: DBG: [[a]] = &(*[[a]]);
16+
foo(&0);
17+
}
18+
19+
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
20+
#[inline]
21+
fn foo(x: *const usize) -> &'static usize {
22+
mir! {
23+
debug a => RET;
24+
{
25+
RET = &*x;
26+
RET = &*x;
27+
Return()
28+
}
29+
}
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//@ build-pass
2+
//@ compile-flags: -g -O
3+
4+
// Regression test for #147485.
5+
6+
#![crate_type = "lib"]
7+
8+
pub fn foo(a: bool, b: bool) -> bool {
9+
let mut c = &a;
10+
if false {
11+
return *c;
12+
}
13+
let d = b && a;
14+
if d {
15+
c = &b;
16+
}
17+
b
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ build-pass
2+
//@ compile-flags: -g -O
3+
4+
// Regression test for #147485.
5+
6+
#![crate_type = "lib"]
7+
8+
pub fn f(x: *const usize) -> &'static usize {
9+
let mut a = unsafe { &*x };
10+
a = unsafe { &*x };
11+
a
12+
}
13+
14+
pub fn g() {
15+
f(&0);
16+
}

0 commit comments

Comments
 (0)