Use `Local`s instead of `Place`s in MIR drop generation
This commit is contained in:
parent
b86e6755b9
commit
3131427784
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue