-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure we handle backwards_incompatible_lint
drops appropriately in drop elaboration
#134486
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -151,15 +151,13 @@ struct DropData { | |
|
||
/// Whether this is a value Drop or a StorageDead. | ||
kind: DropKind, | ||
|
||
/// Whether this is a backwards-incompatible drop lint | ||
backwards_incompatible_lint: bool, | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
pub(crate) enum DropKind { | ||
Value, | ||
Storage, | ||
ForLint, | ||
} | ||
|
||
#[derive(Debug)] | ||
|
@@ -248,7 +246,7 @@ impl Scope { | |
/// use of optimizations in the MIR coroutine transform. | ||
fn needs_cleanup(&self) -> bool { | ||
self.drops.iter().any(|drop| match drop.kind { | ||
DropKind::Value => true, | ||
DropKind::Value | DropKind::ForLint => true, | ||
DropKind::Storage => false, | ||
}) | ||
} | ||
|
@@ -277,12 +275,8 @@ impl DropTree { | |
// represents the block in the tree that should be jumped to once all | ||
// of the required drops have been performed. | ||
let fake_source_info = SourceInfo::outermost(DUMMY_SP); | ||
let fake_data = DropData { | ||
source_info: fake_source_info, | ||
local: Local::MAX, | ||
kind: DropKind::Storage, | ||
backwards_incompatible_lint: false, | ||
}; | ||
let fake_data = | ||
DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage }; | ||
let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]); | ||
Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() } | ||
} | ||
|
@@ -411,6 +405,27 @@ impl DropTree { | |
}; | ||
cfg.terminate(block, drop_node.data.source_info, terminator); | ||
} | ||
DropKind::ForLint => { | ||
let stmt = Statement { | ||
source_info: drop_node.data.source_info, | ||
kind: StatementKind::BackwardIncompatibleDropHint { | ||
place: Box::new(drop_node.data.local.into()), | ||
reason: BackwardIncompatibleDropReason::Edition2024, | ||
}, | ||
}; | ||
cfg.push(block, stmt); | ||
let target = blocks[drop_node.next].unwrap(); | ||
if target != block { | ||
// Diagnostics don't use this `Span` but debuginfo | ||
// might. Since we don't want breakpoints to be placed | ||
// here, especially when this is on an unwind path, we | ||
// use `DUMMY_SP`. | ||
let source_info = | ||
SourceInfo { span: DUMMY_SP, ..drop_node.data.source_info }; | ||
let terminator = TerminatorKind::Goto { target }; | ||
cfg.terminate(block, source_info, terminator); | ||
} | ||
} | ||
// Root nodes don't correspond to a drop. | ||
DropKind::Storage if drop_idx == ROOT_NODE => {} | ||
DropKind::Storage => { | ||
|
@@ -770,12 +785,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
let local = | ||
place.as_local().unwrap_or_else(|| bug!("projection in tail call args")); | ||
|
||
Some(DropData { | ||
source_info, | ||
local, | ||
kind: DropKind::Value, | ||
backwards_incompatible_lint: false, | ||
}) | ||
Some(DropData { source_info, local, kind: DropKind::Value }) | ||
} | ||
Operand::Constant(_) => None, | ||
}) | ||
|
@@ -822,6 +832,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
}); | ||
block = next; | ||
} | ||
DropKind::ForLint => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Previously we were inserting a drop terminator for tail calls. Not certain if this is ever reachable, but it's more correct. |
||
self.cfg.push(block, Statement { | ||
source_info, | ||
kind: StatementKind::BackwardIncompatibleDropHint { | ||
place: Box::new(local.into()), | ||
reason: BackwardIncompatibleDropReason::Edition2024, | ||
}, | ||
}); | ||
} | ||
DropKind::Storage => { | ||
// Only temps and vars need their storage dead. | ||
assert!(local.index() > self.arg_count); | ||
|
@@ -1021,7 +1040,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
drop_kind: DropKind, | ||
) { | ||
let needs_drop = match drop_kind { | ||
DropKind::Value => { | ||
DropKind::Value | DropKind::ForLint => { | ||
if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) { | ||
return; | ||
} | ||
|
@@ -1101,7 +1120,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, | ||
local, | ||
kind: drop_kind, | ||
backwards_incompatible_lint: false, | ||
}); | ||
|
||
return; | ||
|
@@ -1135,8 +1153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
scope.drops.push(DropData { | ||
source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, | ||
local, | ||
kind: DropKind::Value, | ||
backwards_incompatible_lint: true, | ||
kind: DropKind::ForLint, | ||
}); | ||
|
||
return; | ||
|
@@ -1430,25 +1447,38 @@ fn build_scope_drops<'tcx>( | |
continue; | ||
} | ||
|
||
if drop_data.backwards_incompatible_lint { | ||
cfg.push(block, Statement { | ||
source_info, | ||
kind: StatementKind::BackwardIncompatibleDropHint { | ||
place: Box::new(local.into()), | ||
reason: BackwardIncompatibleDropReason::Edition2024, | ||
}, | ||
}); | ||
} else { | ||
unwind_drops.add_entry_point(block, unwind_to); | ||
let next = cfg.start_new_block(); | ||
cfg.terminate(block, source_info, TerminatorKind::Drop { | ||
place: local.into(), | ||
target: next, | ||
unwind: UnwindAction::Continue, | ||
replace: false, | ||
}); | ||
block = next; | ||
unwind_drops.add_entry_point(block, unwind_to); | ||
let next = cfg.start_new_block(); | ||
cfg.terminate(block, source_info, TerminatorKind::Drop { | ||
place: local.into(), | ||
target: next, | ||
unwind: UnwindAction::Continue, | ||
replace: false, | ||
}); | ||
block = next; | ||
} | ||
DropKind::ForLint => { | ||
// If the operand has been moved, and we are not on an unwind | ||
// path, then don't generate the drop. (We only take this into | ||
// account for non-unwind paths so as not to disturb the | ||
// caching mechanism.) | ||
if scope.moved_locals.iter().any(|&o| o == local) { | ||
continue; | ||
} | ||
|
||
if storage_dead_on_unwind { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not certain if we need to handle this unwind block here. |
||
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local); | ||
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind); | ||
unwind_to = unwind_drops.drops[unwind_to].next; | ||
} | ||
|
||
cfg.push(block, Statement { | ||
source_info, | ||
kind: StatementKind::BackwardIncompatibleDropHint { | ||
place: Box::new(local.into()), | ||
reason: BackwardIncompatibleDropReason::Edition2024, | ||
}, | ||
}); | ||
} | ||
DropKind::Storage => { | ||
if storage_dead_on_unwind { | ||
|
@@ -1500,7 +1530,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { | |
unwind_indices.push(unwind_indices[drop_node.next]); | ||
} | ||
} | ||
DropKind::Value => { | ||
DropKind::Value | DropKind::ForLint => { | ||
let unwind_drop = self | ||
.scopes | ||
.unwind_drops | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// MIR for `method_1` after ElaborateDrops | ||
|
||
fn method_1(_1: Guard) -> () { | ||
debug g => _1; | ||
let mut _0: (); | ||
let mut _2: std::result::Result<OtherDrop, ()>; | ||
let mut _3: &Guard; | ||
let _4: &Guard; | ||
let _5: Guard; | ||
let mut _6: &Guard; | ||
let mut _7: isize; | ||
let _8: OtherDrop; | ||
let _9: (); | ||
let mut _10: bool; | ||
let mut _11: isize; | ||
let mut _12: isize; | ||
let mut _13: isize; | ||
scope 1 { | ||
debug other_drop => _8; | ||
} | ||
scope 2 { | ||
debug err => _9; | ||
} | ||
|
||
bb0: { | ||
_10 = const false; | ||
StorageLive(_2); | ||
StorageLive(_3); | ||
StorageLive(_4); | ||
StorageLive(_5); | ||
StorageLive(_6); | ||
_6 = &_1; | ||
_5 = <Guard as Clone>::clone(move _6) -> [return: bb1, unwind: bb13]; | ||
} | ||
|
||
bb1: { | ||
StorageDead(_6); | ||
_4 = &_5; | ||
_3 = &(*_4); | ||
_2 = method_2(move _3) -> [return: bb2, unwind: bb12]; | ||
} | ||
|
||
bb2: { | ||
_10 = const true; | ||
StorageDead(_3); | ||
PlaceMention(_2); | ||
_7 = discriminant(_2); | ||
switchInt(move _7) -> [0: bb5, 1: bb4, otherwise: bb3]; | ||
} | ||
|
||
bb3: { | ||
unreachable; | ||
} | ||
|
||
bb4: { | ||
StorageLive(_9); | ||
_9 = copy ((_2 as Err).0: ()); | ||
_0 = const (); | ||
StorageDead(_9); | ||
goto -> bb7; | ||
} | ||
|
||
bb5: { | ||
StorageLive(_8); | ||
_8 = move ((_2 as Ok).0: OtherDrop); | ||
_0 = const (); | ||
drop(_8) -> [return: bb6, unwind: bb11]; | ||
} | ||
|
||
bb6: { | ||
StorageDead(_8); | ||
goto -> bb7; | ||
} | ||
|
||
bb7: { | ||
backward incompatible drop(_2); | ||
backward incompatible drop(_5); | ||
goto -> bb21; | ||
} | ||
|
||
bb8: { | ||
drop(_5) -> [return: bb9, unwind: bb13]; | ||
} | ||
|
||
bb9: { | ||
StorageDead(_5); | ||
StorageDead(_4); | ||
_10 = const false; | ||
StorageDead(_2); | ||
drop(_1) -> [return: bb10, unwind: bb14]; | ||
} | ||
|
||
bb10: { | ||
return; | ||
} | ||
|
||
bb11 (cleanup): { | ||
goto -> bb25; | ||
} | ||
|
||
bb12 (cleanup): { | ||
drop(_5) -> [return: bb13, unwind terminate(cleanup)]; | ||
} | ||
|
||
bb13 (cleanup): { | ||
drop(_1) -> [return: bb14, unwind terminate(cleanup)]; | ||
} | ||
|
||
bb14 (cleanup): { | ||
resume; | ||
} | ||
|
||
bb15: { | ||
goto -> bb8; | ||
} | ||
|
||
bb16 (cleanup): { | ||
goto -> bb12; | ||
} | ||
|
||
bb17 (cleanup): { | ||
goto -> bb12; | ||
} | ||
|
||
bb18: { | ||
goto -> bb15; | ||
} | ||
|
||
bb19: { | ||
goto -> bb15; | ||
} | ||
|
||
bb20 (cleanup): { | ||
goto -> bb12; | ||
} | ||
|
||
bb21: { | ||
_11 = discriminant(_2); | ||
switchInt(move _11) -> [0: bb18, otherwise: bb19]; | ||
} | ||
|
||
bb22 (cleanup): { | ||
_12 = discriminant(_2); | ||
switchInt(move _12) -> [0: bb16, otherwise: bb20]; | ||
} | ||
|
||
bb23 (cleanup): { | ||
goto -> bb12; | ||
} | ||
|
||
bb24 (cleanup): { | ||
goto -> bb12; | ||
} | ||
|
||
bb25 (cleanup): { | ||
_13 = discriminant(_2); | ||
switchInt(move _13) -> [0: bb23, otherwise: bb24]; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up adjusting this to act like
DropKind::Storage
, but inserting aBackwardIncompatibleDropHint
instead of aStorageDead
. Previously we'd insert a drop terminator here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense.