Skip to content

Commit 7e35729

Browse files
committed
Don't project into NonNull when dropping a Box
1 parent 54a0f38 commit 7e35729

File tree

8 files changed

+168
-10
lines changed

8 files changed

+168
-10
lines changed

Diff for: compiler/rustc_middle/src/mir/tcx.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ impl<'tcx> PlaceTy<'tcx> {
8686
}
8787
}
8888

89+
pub fn multi_projection_ty(
90+
self,
91+
tcx: TyCtxt<'tcx>,
92+
elems: &[PlaceElem<'tcx>],
93+
) -> PlaceTy<'tcx> {
94+
elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
95+
}
96+
8997
/// Convenience wrapper around `projection_ty_core` for
9098
/// `PlaceElem`, where we can just use the `Ty` that is already
9199
/// stored inline on field projection elems.
@@ -167,11 +175,7 @@ impl<'tcx> Place<'tcx> {
167175
where
168176
D: HasLocalDecls<'tcx>,
169177
{
170-
projection
171-
.iter()
172-
.fold(PlaceTy::from_ty(local_decls.local_decls()[local].ty), |place_ty, &elem| {
173-
place_ty.projection_ty(tcx, elem)
174-
})
178+
PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection)
175179
}
176180

177181
pub fn ty<D: ?Sized>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>

Diff for: compiler/rustc_mir_transform/src/elaborate_drop.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub(crate) trait DropElaborator<'a, 'tcx>: fmt::Debug {
8989

9090
// Accessors
9191

92+
fn patch_ref(&self) -> &MirPatch<'tcx>;
9293
fn patch(&mut self) -> &mut MirPatch<'tcx>;
9394
fn body(&self) -> &'a Body<'tcx>;
9495
fn tcx(&self) -> TyCtxt<'tcx>;
@@ -180,7 +181,14 @@ where
180181
{
181182
#[instrument(level = "trace", skip(self), ret)]
182183
fn place_ty(&self, place: Place<'tcx>) -> Ty<'tcx> {
183-
place.ty(self.elaborator.body(), self.tcx()).ty
184+
if place.local < self.elaborator.body().local_decls.next_index() {
185+
place.ty(self.elaborator.body(), self.tcx()).ty
186+
} else {
187+
// We don't have a slice with all the locals, since some are in the patch.
188+
tcx::PlaceTy::from_ty(self.elaborator.patch_ref().local_ty(place.local))
189+
.multi_projection_ty(self.elaborator.tcx(), place.projection)
190+
.ty
191+
}
184192
}
185193

186194
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -410,12 +418,26 @@ where
410418

411419
let unique_place = self.tcx().mk_place_field(self.place, FieldIdx::ZERO, unique_ty);
412420
let nonnull_place = self.tcx().mk_place_field(unique_place, FieldIdx::ZERO, nonnull_ty);
413-
let ptr_place = self.tcx().mk_place_field(nonnull_place, FieldIdx::ZERO, ptr_ty);
414-
let interior = self.tcx().mk_place_deref(ptr_place);
415421

422+
let ptr_local = self.new_temp(ptr_ty);
423+
424+
let interior = self.tcx().mk_place_deref(Place::from(ptr_local));
416425
let interior_path = self.elaborator.deref_subpath(self.path);
417426

418-
self.drop_subpath(interior, interior_path, succ, unwind)
427+
let do_drop_bb = self.drop_subpath(interior, interior_path, succ, unwind);
428+
429+
let setup_bbd = BasicBlockData {
430+
statements: vec![self.assign(
431+
Place::from(ptr_local),
432+
Rvalue::Cast(CastKind::Transmute, Operand::Copy(nonnull_place), ptr_ty),
433+
)],
434+
terminator: Some(Terminator {
435+
kind: TerminatorKind::Goto { target: do_drop_bb },
436+
source_info: self.source_info,
437+
}),
438+
is_cleanup: unwind.is_cleanup(),
439+
};
440+
self.elaborator.patch().new_block(setup_bbd)
419441
}
420442

421443
#[instrument(level = "debug", ret)]

Diff for: compiler/rustc_mir_transform/src/elaborate_drops.rs

+4
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ impl InitializationData<'_, '_> {
138138
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
139139
type Path = MovePathIndex;
140140

141+
fn patch_ref(&self) -> &MirPatch<'tcx> {
142+
&self.patch
143+
}
144+
141145
fn patch(&mut self) -> &mut MirPatch<'tcx> {
142146
&mut self.patch
143147
}

Diff for: compiler/rustc_mir_transform/src/patch.rs

+8
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ impl<'tcx> MirPatch<'tcx> {
166166
Local::new(index)
167167
}
168168

169+
/// Returns the type of a local that's newly-added in the patch.
170+
pub(crate) fn local_ty(&self, local: Local) -> Ty<'tcx> {
171+
let local = local.as_usize();
172+
assert!(local < self.next_local);
173+
let new_local_idx = self.new_locals.len() - (self.next_local - local);
174+
self.new_locals[new_local_idx].ty
175+
}
176+
169177
pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
170178
let block = BasicBlock::new(self.patch_map.len());
171179
debug!("MirPatch: new_block: {:?}: {:?}", block, data);

Diff for: compiler/rustc_mir_transform/src/shim.rs

+3
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ impl fmt::Debug for DropShimElaborator<'_, '_> {
350350
impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
351351
type Path = ();
352352

353+
fn patch_ref(&self) -> &MirPatch<'tcx> {
354+
&self.patch
355+
}
353356
fn patch(&mut self) -> &mut MirPatch<'tcx> {
354357
&mut self.patch
355358
}

Diff for: tests/mir-opt/box_expr.main.ElaborateDrops.diff

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
let mut _7: std::boxed::Box<S>;
1313
+ let mut _8: &mut std::boxed::Box<S>;
1414
+ let mut _9: ();
15+
+ let mut _10: *const S;
1516
scope 1 {
1617
debug x => _1;
1718
}
@@ -68,7 +69,7 @@
6869

6970
bb8 (cleanup): {
7071
- drop(_5) -> [return: bb9, unwind terminate(cleanup)];
71-
+ goto -> bb11;
72+
+ goto -> bb12;
7273
}
7374

7475
bb9 (cleanup): {
@@ -82,6 +83,11 @@
8283
+
8384
+ bb11 (cleanup): {
8485
+ goto -> bb10;
86+
+ }
87+
+
88+
+ bb12 (cleanup): {
89+
+ _10 = copy ((_5.0: std::ptr::Unique<S>).0: std::ptr::NonNull<S>) as *const S (Transmute);
90+
+ goto -> bb11;
8591
}
8692
}
8793

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
- // MIR for `maybe_move` before ElaborateDrops
2+
+ // MIR for `maybe_move` after ElaborateDrops
3+
4+
fn maybe_move(_1: bool, _2: Box<String>) -> Option<String> {
5+
debug cond => _1;
6+
debug thing => _2;
7+
let mut _0: std::option::Option<std::string::String>;
8+
let mut _3: bool;
9+
let mut _4: std::string::String;
10+
+ let mut _5: bool;
11+
+ let mut _6: &mut std::boxed::Box<std::string::String>;
12+
+ let mut _7: ();
13+
+ let mut _8: &mut std::boxed::Box<std::string::String>;
14+
+ let mut _9: ();
15+
+ let mut _10: *const std::string::String;
16+
17+
bb0: {
18+
+ _5 = const false;
19+
+ _5 = const true;
20+
StorageLive(_3);
21+
_3 = copy _1;
22+
switchInt(move _3) -> [0: bb3, otherwise: bb1];
23+
}
24+
25+
bb1: {
26+
StorageLive(_4);
27+
+ _5 = const false;
28+
_4 = move (*_2);
29+
_0 = Option::<String>::Some(move _4);
30+
- drop(_4) -> [return: bb2, unwind: bb6];
31+
+ goto -> bb2;
32+
}
33+
34+
bb2: {
35+
StorageDead(_4);
36+
goto -> bb4;
37+
}
38+
39+
bb3: {
40+
_0 = Option::<String>::None;
41+
goto -> bb4;
42+
}
43+
44+
bb4: {
45+
StorageDead(_3);
46+
- drop(_2) -> [return: bb5, unwind continue];
47+
+ goto -> bb14;
48+
}
49+
50+
bb5: {
51+
return;
52+
}
53+
54+
bb6 (cleanup): {
55+
- drop(_2) -> [return: bb7, unwind terminate(cleanup)];
56+
+ goto -> bb7;
57+
}
58+
59+
bb7 (cleanup): {
60+
resume;
61+
+ }
62+
+
63+
+ bb8: {
64+
+ goto -> bb5;
65+
+ }
66+
+
67+
+ bb9: {
68+
+ _6 = &mut _2;
69+
+ _7 = <Box<String> as Drop>::drop(move _6) -> [return: bb8, unwind: bb7];
70+
+ }
71+
+
72+
+ bb10 (cleanup): {
73+
+ _8 = &mut _2;
74+
+ _9 = <Box<String> as Drop>::drop(move _8) -> [return: bb7, unwind terminate(cleanup)];
75+
+ }
76+
+
77+
+ bb11: {
78+
+ goto -> bb13;
79+
+ }
80+
+
81+
+ bb12: {
82+
+ drop((*_10)) -> [return: bb9, unwind: bb10];
83+
+ }
84+
+
85+
+ bb13: {
86+
+ switchInt(copy _5) -> [0: bb9, otherwise: bb12];
87+
+ }
88+
+
89+
+ bb14: {
90+
+ _10 = copy ((_2.0: std::ptr::Unique<std::string::String>).0: std::ptr::NonNull<std::string::String>) as *const std::string::String (Transmute);
91+
+ goto -> bb11;
92+
}
93+
}
94+

Diff for: tests/mir-opt/box_partial_move.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ test-mir-pass: ElaborateDrops
2+
//@ needs-unwind
3+
4+
#![feature(rustc_attrs, liballoc_internals)]
5+
6+
// EMIT_MIR box_partial_move.maybe_move.ElaborateDrops.diff
7+
fn maybe_move(cond: bool, thing: Box<String>) -> Option<String> {
8+
// CHECK-LABEL: fn maybe_move(
9+
// CHECK: let mut [[PTR:_[0-9]+]]: *const std::string::String;
10+
// CHECK: [[PTR]] = copy ((_2.0: std::ptr::Unique<std::string::String>).0: std::ptr::NonNull<std::string::String>) as *const std::string::String (Transmute);
11+
// CHECK: drop((*[[PTR]]))
12+
if cond { Some(*thing) } else { None }
13+
}
14+
15+
fn main() {
16+
maybe_move(false, Box::new("hello".to_string()));
17+
}

0 commit comments

Comments
 (0)