Use `Local`s instead of `Place`s in MIR drop generation

This commit is contained in:
Matthew Jasper 2019-06-15 20:33:23 +01:00
parent b86e6755b9
commit 3131427784
5 changed files with 81 additions and 100 deletions

View File

@ -127,7 +127,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.schedule_drop_storage_and_value( this.schedule_drop_storage_and_value(
expr_span, expr_span,
scope, scope,
&Place::from(result), result,
value.ty, value.ty,
); );
} }
@ -559,7 +559,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.schedule_drop_storage_and_value( this.schedule_drop_storage_and_value(
upvar_span, upvar_span,
temp_lifetime, temp_lifetime,
&Place::from(temp), temp,
upvar_ty, upvar_ty,
); );
} }

View File

@ -88,7 +88,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.schedule_drop( this.schedule_drop(
expr_span, expr_span,
temp_lifetime, temp_lifetime,
temp_place, temp,
expr_ty, expr_ty,
DropKind::Storage, DropKind::Storage,
); );
@ -101,7 +101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.schedule_drop( this.schedule_drop(
expr_span, expr_span,
temp_lifetime, temp_lifetime,
temp_place, temp,
expr_ty, expr_ty,
DropKind::Value, DropKind::Value,
); );

View File

@ -531,11 +531,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
kind: StatementKind::StorageLive(local_id), kind: StatementKind::StorageLive(local_id),
}, },
); );
let place = Place::from(local_id);
let var_ty = self.local_decls[local_id].ty; let var_ty = self.local_decls[local_id].ty;
let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
self.schedule_drop(span, region_scope, &place, var_ty, DropKind::Storage); self.schedule_drop(span, region_scope, local_id, var_ty, DropKind::Storage);
place Place::Base(PlaceBase::Local(local_id))
} }
pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { pub fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) {
@ -545,7 +544,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.schedule_drop( self.schedule_drop(
span, span,
region_scope, region_scope,
&Place::from(local_id), local_id,
var_ty, var_ty,
DropKind::Value, DropKind::Value,
); );

View File

@ -809,7 +809,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Make sure we drop (parts of) the argument even when not matched on. // Make sure we drop (parts of) the argument even when not matched on.
self.schedule_drop( self.schedule_drop(
pattern.as_ref().map_or(ast_body.span, |pat| pat.span), pattern.as_ref().map_or(ast_body.span, |pat| pat.span),
argument_scope, &place, ty, DropKind::Value, argument_scope, local, ty, DropKind::Value,
); );
if let Some(pattern) = pattern { if let Some(pattern) = pattern {

View File

@ -94,7 +94,7 @@ use std::collections::hash_map::Entry;
use std::mem; use std::mem;
#[derive(Debug)] #[derive(Debug)]
struct Scope<'tcx> { struct Scope {
/// The source scope this scope was created in. /// The source scope this scope was created in.
source_scope: SourceScope, source_scope: SourceScope,
@ -121,7 +121,7 @@ struct Scope<'tcx> {
/// out empty but grows as variables are declared during the /// out empty but grows as variables are declared during the
/// building process. This is a stack, so we always drop from the /// building process. This is a stack, so we always drop from the
/// end of the vector (top of the stack) first. /// end of the vector (top of the stack) first.
drops: Vec<DropData<'tcx>>, drops: Vec<DropData>,
/// The cache for drop chain on “normal” exit into a particular BasicBlock. /// The cache for drop chain on “normal” exit into a particular BasicBlock.
cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>, cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
@ -135,18 +135,18 @@ struct Scope<'tcx> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Scopes<'tcx> { pub struct Scopes<'tcx> {
scopes: Vec<Scope<'tcx>>, scopes: Vec<Scope>,
/// The current set of breakable scopes. See module comment for more details. /// The current set of breakable scopes. See module comment for more details.
breakable_scopes: Vec<BreakableScope<'tcx>>, breakable_scopes: Vec<BreakableScope<'tcx>>,
} }
#[derive(Debug)] #[derive(Debug)]
struct DropData<'tcx> { struct DropData {
/// span where drop obligation was incurred (typically where place was declared) /// span where drop obligation was incurred (typically where place was declared)
span: Span, span: Span,
/// place to drop /// local to drop
location: Place<'tcx>, local: Local,
/// Whether this is a value Drop or a StorageDead. /// Whether this is a value Drop or a StorageDead.
kind: DropKind, kind: DropKind,
@ -223,7 +223,7 @@ impl CachedBlock {
} }
} }
impl<'tcx> Scope<'tcx> { impl Scope {
/// Invalidates all the cached blocks in the scope. /// Invalidates all the cached blocks in the scope.
/// ///
/// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
@ -285,7 +285,7 @@ impl<'tcx> Scopes<'tcx> {
fn pop_scope( fn pop_scope(
&mut self, &mut self,
region_scope: (region::Scope, SourceInfo), region_scope: (region::Scope, SourceInfo),
) -> (Scope<'tcx>, Option<BasicBlock>) { ) -> (Scope, Option<BasicBlock>) {
let scope = self.scopes.pop().unwrap(); let scope = self.scopes.pop().unwrap();
assert_eq!(scope.region_scope, region_scope.0); assert_eq!(scope.region_scope, region_scope.0);
let unwind_to = self.scopes.last() let unwind_to = self.scopes.last()
@ -343,11 +343,11 @@ impl<'tcx> Scopes<'tcx> {
scope_count scope_count
} }
fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item=&mut Scope<'tcx>> + '_ { fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item=&mut Scope> + '_ {
self.scopes.iter_mut().rev() self.scopes.iter_mut().rev()
} }
fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item=&mut Scope<'tcx>> + '_ { fn top_scopes(&mut self, count: usize) -> impl DoubleEndedIterator<Item=&mut Scope> + '_ {
let len = self.len(); let len = self.len();
self.scopes[len - count..].iter_mut() self.scopes[len - count..].iter_mut()
} }
@ -717,11 +717,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
span: Span, span: Span,
region_scope: region::Scope, region_scope: region::Scope,
place: &Place<'tcx>, local: Local,
place_ty: Ty<'tcx>, place_ty: Ty<'tcx>,
) { ) {
self.schedule_drop(span, region_scope, place, place_ty, DropKind::Storage); self.schedule_drop(span, region_scope, local, place_ty, DropKind::Storage);
self.schedule_drop(span, region_scope, place, place_ty, DropKind::Value); self.schedule_drop(span, region_scope, local, place_ty, DropKind::Value);
} }
/// Indicates that `place` should be dropped on exit from /// Indicates that `place` should be dropped on exit from
@ -733,7 +733,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
span: Span, span: Span,
region_scope: region::Scope, region_scope: region::Scope,
place: &Place<'tcx>, local: Local,
place_ty: Ty<'tcx>, place_ty: Ty<'tcx>,
drop_kind: DropKind, drop_kind: DropKind,
) { ) {
@ -741,17 +741,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
match drop_kind { match drop_kind {
DropKind::Value => if !needs_drop { return }, DropKind::Value => if !needs_drop { return },
DropKind::Storage => { DropKind::Storage => {
match *place { if local.index() <= self.arg_count {
Place::Base(PlaceBase::Local(index)) => if index.index() <= self.arg_count { span_bug!(
span_bug!( span, "`schedule_drop` called with local {:?} and arg_count {}",
span, "`schedule_drop` called with index {} and arg_count {}", local,
index.index(), self.arg_count,
self.arg_count, )
)
},
_ => span_bug!(
span, "`schedule_drop` called with non-`Local` place {:?}", place
),
} }
} }
} }
@ -817,14 +812,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
scope.drops.push(DropData { scope.drops.push(DropData {
span: scope_end, span: scope_end,
location: place.clone(), local,
kind: drop_kind, kind: drop_kind,
cached_block: CachedBlock::default(), cached_block: CachedBlock::default(),
}); });
return; return;
} }
} }
span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, place); span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
} }
// Other // Other
@ -867,29 +862,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
bug!("Drop scheduled on top of condition variable") bug!("Drop scheduled on top of condition variable")
} }
DropKind::Storage => { DropKind::Storage => {
// Drop the storage for both value and storage drops. let source_info = top_scope.source_info(top_drop_data.span);
// Only temps and vars need their storage dead. let local = top_drop_data.local;
match top_drop_data.location { assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
Place::Base(PlaceBase::Local(index)) => { self.cfg.push(
let source_info = top_scope.source_info(top_drop_data.span); true_block,
assert_eq!(index, cond_temp, "Drop scheduled on top of condition"); Statement {
self.cfg.push( source_info,
true_block, kind: StatementKind::StorageDead(local)
Statement { },
source_info, );
kind: StatementKind::StorageDead(index) self.cfg.push(
}, false_block,
); Statement {
self.cfg.push( source_info,
false_block, kind: StatementKind::StorageDead(local)
Statement { },
source_info, );
kind: StatementKind::StorageDead(index)
},
);
}
_ => unreachable!(),
}
} }
} }
@ -1020,7 +1009,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn build_scope_drops<'tcx>( fn build_scope_drops<'tcx>(
cfg: &mut CFG<'tcx>, cfg: &mut CFG<'tcx>,
is_generator: bool, is_generator: bool,
scope: &Scope<'tcx>, scope: &Scope,
mut block: BasicBlock, mut block: BasicBlock,
last_unwind_to: BasicBlock, last_unwind_to: BasicBlock,
arg_count: usize, arg_count: usize,
@ -1050,6 +1039,7 @@ fn build_scope_drops<'tcx>(
for drop_idx in (0..scope.drops.len()).rev() { for drop_idx in (0..scope.drops.len()).rev() {
let drop_data = &scope.drops[drop_idx]; let drop_data = &scope.drops[drop_idx];
let source_info = scope.source_info(drop_data.span); let source_info = scope.source_info(drop_data.span);
let local = drop_data.local;
match drop_data.kind { match drop_data.kind {
DropKind::Value => { DropKind::Value => {
let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop) let unwind_to = get_unwind_to(scope, is_generator, drop_idx, generator_drop)
@ -1057,32 +1047,27 @@ fn build_scope_drops<'tcx>(
let next = cfg.start_new_block(); let next = cfg.start_new_block();
cfg.terminate(block, source_info, TerminatorKind::Drop { cfg.terminate(block, source_info, TerminatorKind::Drop {
location: drop_data.location.clone(), location: local.into(),
target: next, target: next,
unwind: Some(unwind_to) unwind: Some(unwind_to)
}); });
block = next; block = next;
} }
DropKind::Storage => { DropKind::Storage => {
// Drop the storage for both value and storage drops.
// Only temps and vars need their storage dead. // Only temps and vars need their storage dead.
match drop_data.location { assert!(local.index() > arg_count);
Place::Base(PlaceBase::Local(index)) if index.index() > arg_count => { cfg.push(block, Statement {
cfg.push(block, Statement { source_info,
source_info, kind: StatementKind::StorageDead(local)
kind: StatementKind::StorageDead(index) });
});
}
_ => unreachable!(),
}
} }
} }
} }
block.unit() block.unit()
} }
fn get_unwind_to<'tcx>( fn get_unwind_to(
scope: &Scope<'tcx>, scope: &Scope,
is_generator: bool, is_generator: bool,
unwind_from: usize, unwind_from: usize,
generator_drop: bool, generator_drop: bool,
@ -1108,7 +1093,7 @@ fn get_unwind_to<'tcx>(
fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>, fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
span: Span, span: Span,
scope: &mut Scope<'tcx>, scope: &mut Scope,
mut target: BasicBlock, mut target: BasicBlock,
generator_drop: bool, generator_drop: bool,
is_generator: bool) is_generator: bool)
@ -1152,26 +1137,20 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
// this is not what clang does. // this is not what clang does.
match drop_data.kind { match drop_data.kind {
DropKind::Storage if is_generator => { DropKind::Storage if is_generator => {
// Only temps and vars need their storage dead. storage_deads.push(Statement {
match drop_data.location { source_info: source_info(drop_data.span),
Place::Base(PlaceBase::Local(index)) => { kind: StatementKind::StorageDead(drop_data.local)
storage_deads.push(Statement { });
source_info: source_info(drop_data.span), if !target_built_by_us {
kind: StatementKind::StorageDead(index) // We cannot add statements to an existing block, so we create a new
}); // block for our StorageDead statements.
if !target_built_by_us { let block = cfg.start_new_cleanup_block();
// We cannot add statements to an existing block, so we create a new let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope };
// block for our StorageDead statements. cfg.terminate(block, source_info,
let block = cfg.start_new_cleanup_block(); TerminatorKind::Goto { target: target });
let source_info = SourceInfo { span: DUMMY_SP, scope: source_scope }; target = block;
cfg.terminate(block, source_info, target_built_by_us = true;
TerminatorKind::Goto { target: target }); }
target = block;
target_built_by_us = true;
}
}
_ => unreachable!(),
};
*drop_data.cached_block.ref_mut(generator_drop) = Some(target); *drop_data.cached_block.ref_mut(generator_drop) = Some(target);
} }
DropKind::Storage => {} DropKind::Storage => {}
@ -1184,12 +1163,15 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
} else { } else {
push_storage_deads(cfg, target, &mut storage_deads); push_storage_deads(cfg, target, &mut storage_deads);
let block = cfg.start_new_cleanup_block(); let block = cfg.start_new_cleanup_block();
cfg.terminate(block, source_info(drop_data.span), cfg.terminate(
TerminatorKind::Drop { block,
location: drop_data.location.clone(), source_info(drop_data.span),
target, TerminatorKind::Drop {
unwind: None location: drop_data.local.into(),
}); target,
unwind: None
},
);
*cached_block = Some(block); *cached_block = Some(block);
target_built_by_us = true; target_built_by_us = true;
block block