Skip to content

Commit 730d5d4

Browse files
committed
Auto merge of #128572 - compiler-errors:fix-elaborate-box-derefs-on-debug, r=saethlin
Fix `ElaborateBoxDerefs` on debug varinfo Slightly simplifies the `ElaborateBoxDerefs` pass to fix cases where it was applying the wrong projections to debug var infos containing places that deref boxes. From what I can tell[^1], we don't actually have any tests (or code anywhere, really) that exercise `debug x => *(...: Box<T>)`, and it's very difficult to trigger this in surface Rust, so I wrote a custom MIR test. What happens is that the pass was turning `*(SOME_PLACE: Box<T>)` into `*(*((((SOME_PLACE).0: Unique<T>).0: NonNull<T>).0: *const T))` in debug var infos. In particular, notice the *double deref*, which was wrong. This is the root cause of #128554, so this PR fixes #128554 as well. The reason that async closures was affected is because of the way that we compute the [`ByMove` body](https://github.com/rust-lang/rust/blob/master/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs), which resulted in `*(...: Box<T>)` in debug var info. But this really has nothing to do with async closures. [^1]: Validated by literally replacing the `if elem == PlaceElem::Deref && base_ty.is_box() { ... }` innards with a `panic!()`, which compiled all of stage2 without panicking.
2 parents 04dff01 + 2e52d61 commit 730d5d4

File tree

4 files changed

+77
-8
lines changed

4 files changed

+77
-8
lines changed

compiler/rustc_mir_transform/src/elaborate_box_derefs.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -116,29 +116,30 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
116116
for debug_info in body.var_debug_info.iter_mut() {
117117
if let VarDebugInfoContents::Place(place) = &mut debug_info.value {
118118
let mut new_projections: Option<Vec<_>> = None;
119-
let mut last_deref = 0;
120119

121-
for (i, (base, elem)) in place.iter_projections().enumerate() {
120+
for (base, elem) in place.iter_projections() {
122121
let base_ty = base.ty(&body.local_decls, tcx).ty;
123122

124123
if elem == PlaceElem::Deref && base_ty.is_box() {
125-
let new_projections = new_projections.get_or_insert_default();
124+
// Clone the projections before us, since now we need to mutate them.
125+
let new_projections =
126+
new_projections.get_or_insert_with(|| base.projection.to_vec());
126127

127128
let (unique_ty, nonnull_ty, ptr_ty) =
128129
build_ptr_tys(tcx, base_ty.boxed_ty(), unique_did, nonnull_did);
129130

130-
new_projections.extend_from_slice(&base.projection[last_deref..]);
131131
new_projections.extend_from_slice(&build_projection(
132132
unique_ty, nonnull_ty, ptr_ty,
133133
));
134134
new_projections.push(PlaceElem::Deref);
135-
136-
last_deref = i;
135+
} else if let Some(new_projections) = new_projections.as_mut() {
136+
// Keep building up our projections list once we've started it.
137+
new_projections.push(elem);
137138
}
138139
}
139140

140-
if let Some(mut new_projections) = new_projections {
141-
new_projections.extend_from_slice(&place.projection[last_deref..]);
141+
// Store the mutated projections if we actually changed something.
142+
if let Some(new_projections) = new_projections {
142143
place.projection = tcx.mk_place_elems(&new_projections);
143144
}
144145
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
- // MIR for `pointee` before ElaborateBoxDerefs
2+
+ // MIR for `pointee` after ElaborateBoxDerefs
3+
4+
fn pointee(_1: Box<i32>) -> () {
5+
- debug foo => (*_1);
6+
+ debug foo => (*(((_1.0: std::ptr::Unique<i32>).0: std::ptr::NonNull<i32>).0: *const i32));
7+
let mut _0: ();
8+
9+
bb0: {
10+
return;
11+
}
12+
}
13+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// skip-filecheck
2+
//@ test-mir-pass: ElaborateBoxDerefs
3+
4+
#![feature(custom_mir, core_intrinsics)]
5+
6+
extern crate core;
7+
use core::intrinsics::mir::*;
8+
9+
// EMIT_MIR elaborate_box_deref_in_debuginfo.pointee.ElaborateBoxDerefs.diff
10+
#[custom_mir(dialect = "built")]
11+
fn pointee(opt: Box<i32>) {
12+
mir!(
13+
debug foo => *opt;
14+
{
15+
Return()
16+
}
17+
)
18+
}
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ aux-build:block-on.rs
2+
//@ edition:2021
3+
//@ run-pass
4+
5+
#![feature(async_closure)]
6+
7+
extern crate block_on;
8+
9+
pub trait Trait {
10+
fn callback(&mut self);
11+
}
12+
impl Trait for (i32,) {
13+
fn callback(&mut self) {
14+
println!("hi {}", self.0);
15+
self.0 += 1;
16+
}
17+
}
18+
19+
async fn call_once(f: impl async FnOnce()) {
20+
f().await;
21+
}
22+
23+
async fn run(mut loader: Box<dyn Trait>) {
24+
let f = async move || {
25+
loader.callback();
26+
loader.callback();
27+
};
28+
call_once(f).await;
29+
}
30+
31+
fn main() {
32+
block_on::block_on(async {
33+
run(Box::new((42,))).await;
34+
});
35+
}

0 commit comments

Comments
 (0)