-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Desugaring of drop and replace at MIR build #107844
Changes from all 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 |
---|---|---|
|
@@ -91,7 +91,7 @@ use rustc_middle::middle::region; | |
use rustc_middle::mir::*; | ||
use rustc_middle::thir::{Expr, LintLevel}; | ||
|
||
use rustc_span::{Span, DUMMY_SP}; | ||
use rustc_span::{DesugaringKind, Span, DUMMY_SP}; | ||
|
||
#[derive(Debug)] | ||
pub struct Scopes<'tcx> { | ||
|
@@ -1118,24 +1118,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
} | ||
|
||
/// Utility function for *non*-scope code to build their own drops | ||
/// Force a drop at this point in the MIR by creating a new block. | ||
pub(crate) fn build_drop_and_replace( | ||
&mut self, | ||
block: BasicBlock, | ||
span: Span, | ||
place: Place<'tcx>, | ||
value: Operand<'tcx>, | ||
value: Rvalue<'tcx>, | ||
) -> BlockAnd<()> { | ||
let span = self.tcx.with_stable_hashing_context(|hcx| { | ||
span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx) | ||
}); | ||
let source_info = self.source_info(span); | ||
let next_target = self.cfg.start_new_block(); | ||
|
||
// create the new block for the assignment | ||
let assign = self.cfg.start_new_block(); | ||
self.cfg.push_assign(assign, source_info, place, value.clone()); | ||
|
||
// create the new block for the assignment in the case of unwinding | ||
let assign_unwind = self.cfg.start_new_cleanup_block(); | ||
self.cfg.push_assign(assign_unwind, source_info, place, value.clone()); | ||
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. Having the assignment even in the unwind case is a bit surprising. This is the current behaviour, so ok. Should eventually be removed in the future? 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. As long as drop can unwind, it is necessary to avoid leaving partially destroyed places behind. See #30380 for an example. |
||
|
||
self.cfg.terminate( | ||
block, | ||
source_info, | ||
TerminatorKind::DropAndReplace { place, value, target: next_target, unwind: None }, | ||
TerminatorKind::Drop { place, target: assign, unwind: Some(assign_unwind) }, | ||
); | ||
self.diverge_from(block); | ||
|
||
next_target.unit() | ||
assign.unit() | ||
} | ||
|
||
/// Creates an `Assert` terminator and return the success block. | ||
|
@@ -1413,8 +1424,15 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind { | |
fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) { | ||
let term = &mut cfg.block_data_mut(from).terminator_mut(); | ||
match &mut term.kind { | ||
TerminatorKind::Drop { unwind, .. } | ||
| TerminatorKind::DropAndReplace { unwind, .. } | ||
TerminatorKind::Drop { unwind, .. } => { | ||
if let Some(unwind) = *unwind { | ||
let source_info = term.source_info; | ||
cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to }); | ||
} else { | ||
*unwind = Some(to); | ||
} | ||
} | ||
TerminatorKind::DropAndReplace { unwind, .. } | ||
| TerminatorKind::FalseUnwind { unwind, .. } | ||
| TerminatorKind::Call { cleanup: unwind, .. } | ||
| TerminatorKind::Assert { cleanup: unwind, .. } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer; | |
use rustc_mir_dataflow::MoveDataParamEnv; | ||
use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; | ||
use rustc_mir_dataflow::{Analysis, ResultsCursor}; | ||
use rustc_span::Span; | ||
use rustc_span::{DesugaringKind, Span}; | ||
use rustc_target::abi::VariantIdx; | ||
use std::fmt; | ||
|
||
|
@@ -425,10 +425,19 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { | |
bb, | ||
), | ||
LookupResult::Parent(..) => { | ||
self.tcx.sess.delay_span_bug( | ||
terminator.source_info.span, | ||
&format!("drop of untracked value {:?}", bb), | ||
); | ||
if !matches!( | ||
terminator.source_info.span.desugaring_kind(), | ||
Some(DesugaringKind::Replace), | ||
) { | ||
self.tcx.sess.delay_span_bug( | ||
terminator.source_info.span, | ||
&format!("drop of untracked value {:?}", bb), | ||
); | ||
} | ||
// A drop and replace behind a pointer/array/whatever. | ||
// The borrow checker requires that these locations are initialized before the assignment, | ||
// so we just leave an unconditional drop. | ||
assert!(!data.is_cleanup); | ||
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 sure I have a clear idea of MIR looks like in that case. Do you have an example? 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.
the body of
Under normal conditions, dropping something behind a pointer would be bad ( 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. In that case, should we assert that we will assign to 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. That's what the check for |
||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
- // MIR for `main` before ElaborateDrops | ||
+ // MIR for `main` after ElaborateDrops | ||
|
||
fn main() -> () { | ||
let mut _0: (); // return place in scope 0 at $DIR/basic_assignment.rs:+0:11: +0:11 | ||
let _1: bool; // in scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17 | ||
let mut _3: bool; // in scope 0 at $DIR/basic_assignment.rs:+6:16: +6:24 | ||
let mut _6: std::option::Option<std::boxed::Box<u32>>; // in scope 0 at $DIR/basic_assignment.rs:+13:14: +13:20 | ||
scope 1 { | ||
debug nodrop_x => _1; // in scope 1 at $DIR/basic_assignment.rs:+1:9: +1:17 | ||
let _2: bool; // in scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17 | ||
scope 2 { | ||
debug nodrop_y => _2; // in scope 2 at $DIR/basic_assignment.rs:+2:9: +2:17 | ||
let _4: std::option::Option<std::boxed::Box<u32>>; // in scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15 | ||
scope 3 { | ||
debug drop_x => _4; // in scope 3 at $DIR/basic_assignment.rs:+8:9: +8:15 | ||
let _5: std::option::Option<std::boxed::Box<u32>>; // in scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15 | ||
scope 4 { | ||
debug drop_y => _5; // in scope 4 at $DIR/basic_assignment.rs:+9:9: +9:15 | ||
} | ||
} | ||
} | ||
} | ||
|
||
bb0: { | ||
StorageLive(_1); // scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17 | ||
_1 = const false; // scope 0 at $DIR/basic_assignment.rs:+1:20: +1:25 | ||
StorageLive(_2); // scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17 | ||
StorageLive(_3); // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24 | ||
_3 = _1; // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24 | ||
_2 = move _3; // scope 2 at $DIR/basic_assignment.rs:+6:5: +6:24 | ||
StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:+6:23: +6:24 | ||
StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15 | ||
_4 = Option::<Box<u32>>::None; // scope 2 at $DIR/basic_assignment.rs:+8:36: +8:40 | ||
StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15 | ||
StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20 | ||
_6 = move _4; // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20 | ||
- drop(_5) -> [return: bb1, unwind: bb2]; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11 | ||
+ goto -> bb1; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11 | ||
} | ||
|
||
bb1: { | ||
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11 | ||
- drop(_6) -> [return: bb3, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 | ||
+ goto -> bb3; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 | ||
} | ||
|
||
bb2 (cleanup): { | ||
_5 = move _6; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11 | ||
drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 | ||
} | ||
|
||
bb3: { | ||
StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20 | ||
_0 = const (); // scope 0 at $DIR/basic_assignment.rs:+0:11: +14:2 | ||
drop(_5) -> [return: bb4, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
} | ||
|
||
bb4: { | ||
StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
- drop(_4) -> bb5; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
+ goto -> bb5; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
} | ||
|
||
bb5: { | ||
StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
return; // scope 0 at $DIR/basic_assignment.rs:+14:2: +14:2 | ||
} | ||
|
||
bb6 (cleanup): { | ||
drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
} | ||
|
||
bb7 (cleanup): { | ||
- drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
+ goto -> bb8; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2 | ||
} | ||
|
||
bb8 (cleanup): { | ||
resume; // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2 | ||
} | ||
} | ||
|
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.
It's a little surprising to me that this wasn't
.as_local_rvalue
already. Were we just less precise than we could be before?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.
Oh no, I guess this change is because
build_drop_and_replace
was changed to take an rvalue.