Skip to content

Commit 7104e01

Browse files
authored
Rollup merge of rust-lang#131146 - beepster4096:box_drop_flags, r=wesleywiser
Stop clearing box's drop flags early Ever since rust-lang#100036, drop flags have been incorrectly cleared when destructors are called. This only does anything in a very specific case involving Box, leading to the fields of the Box not being dropped when they should. This PR fixes that. Fixes rust-lang#131082
2 parents ad211ce + 1bd8217 commit 7104e01

File tree

6 files changed

+268
-13
lines changed

6 files changed

+268
-13
lines changed

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

+9-9
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,19 @@ where
460460

461461
if adt.is_box() {
462462
// we need to drop the inside of the box before running the destructor
463-
let succ = self.destructor_call_block(contents_drop);
463+
let destructor = self.destructor_call_block(contents_drop);
464464
let unwind = contents_drop
465465
.1
466466
.map(|unwind| self.destructor_call_block((unwind, Unwind::InCleanup)));
467467

468-
self.open_drop_for_box_contents(adt, args, succ, unwind)
468+
let boxed_drop = self.open_drop_for_box_contents(adt, args, destructor, unwind);
469+
470+
// the drop flag will be at the end of contents_drop
471+
self.drop_flag_test_block(boxed_drop, self.succ, unwind)
469472
} else if adt.has_dtor(self.tcx()) {
473+
// We don't need to test drop flags here because
474+
// this path is only taken with DropShimElaborator
475+
// where testing drop flags is a noop
470476
self.destructor_call_block(contents_drop)
471477
} else {
472478
contents_drop.0
@@ -659,13 +665,7 @@ where
659665
}),
660666
is_cleanup: unwind.is_cleanup(),
661667
};
662-
663-
let destructor_block = self.elaborator.patch().new_block(result);
664-
665-
let block_start = Location { block: destructor_block, statement_index: 0 };
666-
self.elaborator.clear_drop_flag(block_start, self.path, DropFlagMode::Shallow);
667-
668-
self.drop_flag_test_block(destructor_block, succ, unwind)
668+
self.elaborator.patch().new_block(result)
669669
}
670670

671671
/// Create a loop that drops an array:

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
236236
}
237237

238238
impl fmt::Debug for ElaborateDropsCtxt<'_, '_> {
239-
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
240-
Ok(())
239+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240+
f.debug_struct("ElaborateDropsCtxt").finish_non_exhaustive()
241241
}
242242
}
243243

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ pub(super) struct DropShimElaborator<'a, 'tcx> {
339339
}
340340

341341
impl fmt::Debug for DropShimElaborator<'_, '_> {
342-
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
343-
Ok(())
342+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
343+
f.debug_struct("DropShimElaborator").finish_non_exhaustive()
344344
}
345345
}
346346

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
- // MIR for `main` before ElaborateDrops
2+
+ // MIR for `main` after ElaborateDrops
3+
4+
fn main() -> () {
5+
let mut _0: ();
6+
let _1: std::boxed::Box<HasDrop, DropAllocator>;
7+
let mut _2: HasDrop;
8+
let mut _3: DropAllocator;
9+
let mut _4: bool;
10+
let _5: ();
11+
let mut _6: HasDrop;
12+
let _7: ();
13+
let mut _8: std::boxed::Box<HasDrop, DropAllocator>;
14+
+ let mut _9: bool;
15+
+ let mut _10: &mut std::boxed::Box<HasDrop, DropAllocator>;
16+
+ let mut _11: ();
17+
+ let mut _12: &mut std::boxed::Box<HasDrop, DropAllocator>;
18+
+ let mut _13: ();
19+
+ let mut _14: &mut std::boxed::Box<HasDrop, DropAllocator>;
20+
+ let mut _15: ();
21+
scope 1 {
22+
debug b => _1;
23+
}
24+
25+
bb0: {
26+
+ _9 = const false;
27+
StorageLive(_1);
28+
StorageLive(_2);
29+
_2 = HasDrop;
30+
StorageLive(_3);
31+
_3 = DropAllocator;
32+
_1 = Box::<HasDrop, DropAllocator>::new_in(move _2, move _3) -> [return: bb1, unwind: bb11];
33+
}
34+
35+
bb1: {
36+
+ _9 = const true;
37+
StorageDead(_3);
38+
StorageDead(_2);
39+
StorageLive(_4);
40+
_4 = const true;
41+
switchInt(move _4) -> [0: bb4, otherwise: bb2];
42+
}
43+
44+
bb2: {
45+
StorageLive(_5);
46+
StorageLive(_6);
47+
_6 = move (*_1);
48+
_5 = std::mem::drop::<HasDrop>(move _6) -> [return: bb3, unwind: bb9];
49+
}
50+
51+
bb3: {
52+
StorageDead(_6);
53+
StorageDead(_5);
54+
_0 = const ();
55+
goto -> bb6;
56+
}
57+
58+
bb4: {
59+
StorageLive(_7);
60+
StorageLive(_8);
61+
+ _9 = const false;
62+
_8 = move _1;
63+
_7 = std::mem::drop::<Box<HasDrop, DropAllocator>>(move _8) -> [return: bb5, unwind: bb8];
64+
}
65+
66+
bb5: {
67+
StorageDead(_8);
68+
StorageDead(_7);
69+
_0 = const ();
70+
goto -> bb6;
71+
}
72+
73+
bb6: {
74+
StorageDead(_4);
75+
- drop(_1) -> [return: bb7, unwind continue];
76+
+ goto -> bb22;
77+
}
78+
79+
bb7: {
80+
+ _9 = const false;
81+
StorageDead(_1);
82+
return;
83+
}
84+
85+
bb8 (cleanup): {
86+
- drop(_8) -> [return: bb10, unwind terminate(cleanup)];
87+
+ goto -> bb10;
88+
}
89+
90+
bb9 (cleanup): {
91+
- drop(_6) -> [return: bb10, unwind terminate(cleanup)];
92+
+ goto -> bb10;
93+
}
94+
95+
bb10 (cleanup): {
96+
- drop(_1) -> [return: bb13, unwind terminate(cleanup)];
97+
+ goto -> bb27;
98+
}
99+
100+
bb11 (cleanup): {
101+
- drop(_3) -> [return: bb12, unwind terminate(cleanup)];
102+
+ goto -> bb12;
103+
}
104+
105+
bb12 (cleanup): {
106+
- drop(_2) -> [return: bb13, unwind terminate(cleanup)];
107+
+ goto -> bb13;
108+
}
109+
110+
bb13 (cleanup): {
111+
resume;
112+
+ }
113+
+
114+
+ bb14: {
115+
+ _9 = const false;
116+
+ goto -> bb7;
117+
+ }
118+
+
119+
+ bb15 (cleanup): {
120+
+ drop((_1.1: DropAllocator)) -> [return: bb13, unwind terminate(cleanup)];
121+
+ }
122+
+
123+
+ bb16 (cleanup): {
124+
+ switchInt(copy _9) -> [0: bb13, otherwise: bb15];
125+
+ }
126+
+
127+
+ bb17: {
128+
+ drop((_1.1: DropAllocator)) -> [return: bb14, unwind: bb13];
129+
+ }
130+
+
131+
+ bb18: {
132+
+ switchInt(copy _9) -> [0: bb14, otherwise: bb17];
133+
+ }
134+
+
135+
+ bb19: {
136+
+ _10 = &mut _1;
137+
+ _11 = <Box<HasDrop, DropAllocator> as Drop>::drop(move _10) -> [return: bb18, unwind: bb16];
138+
+ }
139+
+
140+
+ bb20 (cleanup): {
141+
+ _12 = &mut _1;
142+
+ _13 = <Box<HasDrop, DropAllocator> as Drop>::drop(move _12) -> [return: bb16, unwind terminate(cleanup)];
143+
+ }
144+
+
145+
+ bb21: {
146+
+ goto -> bb19;
147+
+ }
148+
+
149+
+ bb22: {
150+
+ switchInt(copy _9) -> [0: bb7, otherwise: bb21];
151+
+ }
152+
+
153+
+ bb23 (cleanup): {
154+
+ drop((_1.1: DropAllocator)) -> [return: bb13, unwind terminate(cleanup)];
155+
+ }
156+
+
157+
+ bb24 (cleanup): {
158+
+ switchInt(copy _9) -> [0: bb13, otherwise: bb23];
159+
+ }
160+
+
161+
+ bb25 (cleanup): {
162+
+ _14 = &mut _1;
163+
+ _15 = <Box<HasDrop, DropAllocator> as Drop>::drop(move _14) -> [return: bb24, unwind terminate(cleanup)];
164+
+ }
165+
+
166+
+ bb26 (cleanup): {
167+
+ goto -> bb25;
168+
+ }
169+
+
170+
+ bb27 (cleanup): {
171+
+ switchInt(copy _9) -> [0: bb13, otherwise: bb26];
172+
}
173+
}
174+

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

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// skip-filecheck
2+
//@ test-mir-pass: ElaborateDrops
3+
#![feature(allocator_api)]
4+
5+
// Regression test for #131082.
6+
// Testing that the allocator of a Box is dropped in conditional drops
7+
8+
use std::alloc::{AllocError, Allocator, Global, Layout};
9+
use std::ptr::NonNull;
10+
11+
struct DropAllocator;
12+
13+
unsafe impl Allocator for DropAllocator {
14+
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
15+
Global.allocate(layout)
16+
}
17+
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
18+
Global.deallocate(ptr, layout);
19+
}
20+
}
21+
impl Drop for DropAllocator {
22+
fn drop(&mut self) {}
23+
}
24+
25+
struct HasDrop;
26+
impl Drop for HasDrop {
27+
fn drop(&mut self) {}
28+
}
29+
30+
// EMIT_MIR box_conditional_drop_allocator.main.ElaborateDrops.diff
31+
fn main() {
32+
let b = Box::new_in(HasDrop, DropAllocator);
33+
if true {
34+
drop(*b);
35+
} else {
36+
drop(b);
37+
}
38+
}

Diff for: tests/ui/drop/box-conditional-drop-allocator.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ run-pass
2+
#![feature(allocator_api)]
3+
4+
// Regression test for #131082.
5+
// Testing that the allocator of a Box is dropped in conditional drops
6+
7+
use std::alloc::{AllocError, Allocator, Global, Layout};
8+
use std::cell::Cell;
9+
use std::ptr::NonNull;
10+
11+
struct DropCheckingAllocator<'a>(&'a Cell<bool>);
12+
13+
unsafe impl Allocator for DropCheckingAllocator<'_> {
14+
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
15+
Global.allocate(layout)
16+
}
17+
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
18+
Global.deallocate(ptr, layout);
19+
}
20+
}
21+
impl Drop for DropCheckingAllocator<'_> {
22+
fn drop(&mut self) {
23+
self.0.set(true);
24+
}
25+
}
26+
27+
struct HasDrop;
28+
impl Drop for HasDrop {
29+
fn drop(&mut self) {}
30+
}
31+
32+
fn main() {
33+
let dropped = Cell::new(false);
34+
{
35+
let b = Box::new_in(HasDrop, DropCheckingAllocator(&dropped));
36+
if true {
37+
drop(*b);
38+
} else {
39+
drop(b);
40+
}
41+
}
42+
assert!(dropped.get());
43+
}

0 commit comments

Comments
 (0)