Auto merge of #44308 - eddyb:local-index, r=arielb1
[MIR] Restrict ProjectionElem::Index and Storage{Live,Dead} to Local. (see #44285) r? @nikomatsakis
This commit is contained in:
commit
2f1ef9ef11
@ -901,10 +901,10 @@ pub enum StatementKind<'tcx> {
|
|||||||
SetDiscriminant { lvalue: Lvalue<'tcx>, variant_index: usize },
|
SetDiscriminant { lvalue: Lvalue<'tcx>, variant_index: usize },
|
||||||
|
|
||||||
/// Start a live range for the storage of the local.
|
/// Start a live range for the storage of the local.
|
||||||
StorageLive(Lvalue<'tcx>),
|
StorageLive(Local),
|
||||||
|
|
||||||
/// End the current live range for the storage of the local.
|
/// End the current live range for the storage of the local.
|
||||||
StorageDead(Lvalue<'tcx>),
|
StorageDead(Local),
|
||||||
|
|
||||||
/// Execute a piece of inline Assembly.
|
/// Execute a piece of inline Assembly.
|
||||||
InlineAsm {
|
InlineAsm {
|
||||||
@ -1077,12 +1077,12 @@ pub enum ProjectionElem<'tcx, V, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
||||||
/// and the index is an operand.
|
/// and the index is a local.
|
||||||
pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>, Ty<'tcx>>;
|
pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Local, Ty<'tcx>>;
|
||||||
|
|
||||||
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
||||||
/// and the index is an operand.
|
/// and the index is a local.
|
||||||
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>, Ty<'tcx>>;
|
pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>;
|
||||||
|
|
||||||
newtype_index!(Field, "field");
|
newtype_index!(Field, "field");
|
||||||
|
|
||||||
@ -1099,7 +1099,7 @@ impl<'tcx> Lvalue<'tcx> {
|
|||||||
self.elem(ProjectionElem::Downcast(adt_def, variant_index))
|
self.elem(ProjectionElem::Downcast(adt_def, variant_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
|
pub fn index(self, index: Local) -> Lvalue<'tcx> {
|
||||||
self.elem(ProjectionElem::Index(index))
|
self.elem(ProjectionElem::Index(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1701,8 +1701,8 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
|
|||||||
lvalue: lvalue.fold_with(folder),
|
lvalue: lvalue.fold_with(folder),
|
||||||
variant_index,
|
variant_index,
|
||||||
},
|
},
|
||||||
StorageLive(ref lval) => StorageLive(lval.fold_with(folder)),
|
StorageLive(ref local) => StorageLive(local.fold_with(folder)),
|
||||||
StorageDead(ref lval) => StorageDead(lval.fold_with(folder)),
|
StorageDead(ref local) => StorageDead(local.fold_with(folder)),
|
||||||
InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
|
InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
|
||||||
asm: asm.clone(),
|
asm: asm.clone(),
|
||||||
outputs: outputs.fold_with(folder),
|
outputs: outputs.fold_with(folder),
|
||||||
@ -1732,9 +1732,9 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
|
|||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
|
Assign(ref lval, ref rval) => { lval.visit_with(visitor) || rval.visit_with(visitor) }
|
||||||
SetDiscriminant { ref lvalue, .. } |
|
SetDiscriminant { ref lvalue, .. } => lvalue.visit_with(visitor),
|
||||||
StorageLive(ref lvalue) |
|
StorageLive(ref local) |
|
||||||
StorageDead(ref lvalue) => lvalue.visit_with(visitor),
|
StorageDead(ref local) => local.visit_with(visitor),
|
||||||
InlineAsm { ref outputs, ref inputs, .. } =>
|
InlineAsm { ref outputs, ref inputs, .. } =>
|
||||||
outputs.visit_with(visitor) || inputs.visit_with(visitor),
|
outputs.visit_with(visitor) || inputs.visit_with(visitor),
|
||||||
|
|
||||||
|
@ -256,7 +256,9 @@ macro_rules! make_mir_visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local(&mut self,
|
fn visit_local(&mut self,
|
||||||
_local: & $($mutability)* Local) {
|
_local: & $($mutability)* Local,
|
||||||
|
_context: LvalueContext<'tcx>,
|
||||||
|
_location: Location) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_visibility_scope(&mut self,
|
fn visit_visibility_scope(&mut self,
|
||||||
@ -358,11 +360,11 @@ macro_rules! make_mir_visitor {
|
|||||||
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
|
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
|
||||||
self.visit_lvalue(lvalue, LvalueContext::Store, location);
|
self.visit_lvalue(lvalue, LvalueContext::Store, location);
|
||||||
}
|
}
|
||||||
StatementKind::StorageLive(ref $($mutability)* lvalue) => {
|
StatementKind::StorageLive(ref $($mutability)* local) => {
|
||||||
self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
|
self.visit_local(local, LvalueContext::StorageLive, location);
|
||||||
}
|
}
|
||||||
StatementKind::StorageDead(ref $($mutability)* lvalue) => {
|
StatementKind::StorageDead(ref $($mutability)* local) => {
|
||||||
self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
|
self.visit_local(local, LvalueContext::StorageDead, location);
|
||||||
}
|
}
|
||||||
StatementKind::InlineAsm { ref $($mutability)* outputs,
|
StatementKind::InlineAsm { ref $($mutability)* outputs,
|
||||||
ref $($mutability)* inputs,
|
ref $($mutability)* inputs,
|
||||||
@ -610,7 +612,7 @@ macro_rules! make_mir_visitor {
|
|||||||
location: Location) {
|
location: Location) {
|
||||||
match *lvalue {
|
match *lvalue {
|
||||||
Lvalue::Local(ref $($mutability)* local) => {
|
Lvalue::Local(ref $($mutability)* local) => {
|
||||||
self.visit_local(local);
|
self.visit_local(local, context, location);
|
||||||
}
|
}
|
||||||
Lvalue::Static(ref $($mutability)* static_) => {
|
Lvalue::Static(ref $($mutability)* static_) => {
|
||||||
self.visit_static(static_, context, location);
|
self.visit_static(static_, context, location);
|
||||||
@ -662,8 +664,8 @@ macro_rules! make_mir_visitor {
|
|||||||
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
|
ProjectionElem::Field(_field, ref $($mutability)* ty) => {
|
||||||
self.visit_ty(ty, Lookup::Loc(location));
|
self.visit_ty(ty, Lookup::Loc(location));
|
||||||
}
|
}
|
||||||
ProjectionElem::Index(ref $($mutability)* operand) => {
|
ProjectionElem::Index(ref $($mutability)* local) => {
|
||||||
self.visit_operand(operand, location);
|
self.visit_local(local, LvalueContext::Consume, location);
|
||||||
}
|
}
|
||||||
ProjectionElem::ConstantIndex { offset: _,
|
ProjectionElem::ConstantIndex { offset: _,
|
||||||
min_length: _,
|
min_length: _,
|
||||||
|
@ -421,7 +421,7 @@ macro_rules! CopyImpls {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId }
|
CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId, ::mir::Local }
|
||||||
|
|
||||||
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
|
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
|
||||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
|
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
|
||||||
|
@ -212,11 +212,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx>
|
|||||||
// ignored by borrowck
|
// ignored by borrowck
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementKind::StorageDead(ref lvalue) => {
|
StatementKind::StorageDead(local) => {
|
||||||
// causes non-drop values to be dropped.
|
// causes non-drop values to be dropped.
|
||||||
self.consume_lvalue(ContextKind::StorageDead.new(location),
|
self.consume_lvalue(ContextKind::StorageDead.new(location),
|
||||||
ConsumeKind::Consume,
|
ConsumeKind::Consume,
|
||||||
(lvalue, span),
|
(&Lvalue::Local(local), span),
|
||||||
flow_state)
|
flow_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -710,7 +710,7 @@ mod restrictions {
|
|||||||
|
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::mir::{Lvalue, Mir, Operand, ProjectionElem};
|
use rustc::mir::{Lvalue, Mir, ProjectionElem};
|
||||||
|
|
||||||
pub(super) struct Restrictions<'c, 'tcx: 'c> {
|
pub(super) struct Restrictions<'c, 'tcx: 'c> {
|
||||||
mir: &'c Mir<'tcx>,
|
mir: &'c Mir<'tcx>,
|
||||||
@ -809,12 +809,7 @@ mod restrictions {
|
|||||||
ProjectionElem::Downcast(..) |
|
ProjectionElem::Downcast(..) |
|
||||||
ProjectionElem::Subslice { .. } |
|
ProjectionElem::Subslice { .. } |
|
||||||
ProjectionElem::ConstantIndex { .. } |
|
ProjectionElem::ConstantIndex { .. } |
|
||||||
ProjectionElem::Index(Operand::Constant(..)) => {
|
ProjectionElem::Index(_) => {
|
||||||
cursor = &proj.base;
|
|
||||||
continue 'cursor;
|
|
||||||
}
|
|
||||||
ProjectionElem::Index(Operand::Consume(ref index)) => {
|
|
||||||
self.lvalue_stack.push(index); // FIXME: did old borrowck do this?
|
|
||||||
cursor = &proj.base;
|
cursor = &proj.base;
|
||||||
continue 'cursor;
|
continue 'cursor;
|
||||||
}
|
}
|
||||||
@ -1004,7 +999,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
("", format!(""), None), // (dont emit downcast info)
|
("", format!(""), None), // (dont emit downcast info)
|
||||||
ProjectionElem::Field(field, _ty) =>
|
ProjectionElem::Field(field, _ty) =>
|
||||||
("", format!(".{}", field.index()), None),
|
("", format!(".{}", field.index()), None),
|
||||||
ProjectionElem::Index(ref index) =>
|
ProjectionElem::Index(index) =>
|
||||||
("", format!(""), Some(index)),
|
("", format!(""), Some(index)),
|
||||||
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
|
ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
|
||||||
("", format!("[{} of {}]", offset, min_length), None),
|
("", format!("[{} of {}]", offset, min_length), None),
|
||||||
@ -1021,23 +1016,11 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
self.append_lvalue_to_string(&proj.base, buf);
|
self.append_lvalue_to_string(&proj.base, buf);
|
||||||
if let Some(index) = index_operand {
|
if let Some(index) = index_operand {
|
||||||
buf.push_str("[");
|
buf.push_str("[");
|
||||||
self.append_operand_to_string(index, buf);
|
self.append_lvalue_to_string(&Lvalue::Local(index), buf);
|
||||||
buf.push_str("]");
|
buf.push_str("]");
|
||||||
} else {
|
} else {
|
||||||
buf.push_str(&suffix);
|
buf.push_str(&suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_operand_to_string(&self, operand: &Operand, buf: &mut String) {
|
|
||||||
match *operand {
|
|
||||||
Operand::Consume(ref lvalue) => {
|
|
||||||
self.append_lvalue_to_string(lvalue, buf);
|
|
||||||
}
|
|
||||||
Operand::Constant(ref constant) => {
|
|
||||||
buf.push_str(&format!("{:?}", constant));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
// region_scope=None so lvalue indexes live forever. They are scalars so they
|
// region_scope=None so lvalue indexes live forever. They are scalars so they
|
||||||
// do not need storage annotations, and they are often copied between
|
// do not need storage annotations, and they are often copied between
|
||||||
// places.
|
// places.
|
||||||
let idx = unpack!(block = this.as_operand(block, None, index));
|
let idx = unpack!(block = this.as_temp(block, None, index));
|
||||||
|
|
||||||
// bounds check:
|
// bounds check:
|
||||||
let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
|
let (len, lt) = (this.temp(usize_ty.clone(), expr_span),
|
||||||
@ -70,12 +70,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
&len, Rvalue::Len(slice.clone()));
|
&len, Rvalue::Len(slice.clone()));
|
||||||
this.cfg.push_assign(block, source_info, // lt = idx < len
|
this.cfg.push_assign(block, source_info, // lt = idx < len
|
||||||
<, Rvalue::BinaryOp(BinOp::Lt,
|
<, Rvalue::BinaryOp(BinOp::Lt,
|
||||||
idx.clone(),
|
Operand::Consume(Lvalue::Local(idx)),
|
||||||
Operand::Consume(len.clone())));
|
Operand::Consume(len.clone())));
|
||||||
|
|
||||||
let msg = AssertMessage::BoundsCheck {
|
let msg = AssertMessage::BoundsCheck {
|
||||||
len: Operand::Consume(len),
|
len: Operand::Consume(len),
|
||||||
index: idx.clone()
|
index: Operand::Consume(Lvalue::Local(idx))
|
||||||
};
|
};
|
||||||
let success = this.assert(block, Operand::Consume(lt), true,
|
let success = this.assert(block, Operand::Consume(lt), true,
|
||||||
msg, expr_span);
|
msg, expr_span);
|
||||||
@ -127,7 +127,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
Some(Category::Lvalue) => false,
|
Some(Category::Lvalue) => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
});
|
});
|
||||||
this.as_temp(block, expr.temp_lifetime, expr)
|
let temp = unpack!(block = this.as_temp(block, expr.temp_lifetime, expr));
|
||||||
|
block.and(Lvalue::Local(temp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
Category::Rvalue(..) => {
|
Category::Rvalue(..) => {
|
||||||
let operand =
|
let operand =
|
||||||
unpack!(block = this.as_temp(block, scope, expr));
|
unpack!(block = this.as_temp(block, scope, expr));
|
||||||
block.and(Operand::Consume(operand))
|
block.and(Operand::Consume(Lvalue::Local(operand)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,23 +96,23 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
ExprKind::Box { value } => {
|
ExprKind::Box { value } => {
|
||||||
let value = this.hir.mirror(value);
|
let value = this.hir.mirror(value);
|
||||||
let result = this.temp(expr.ty, expr_span);
|
let result = this.local_decls.push(LocalDecl::new_temp(expr.ty, expr_span));
|
||||||
this.cfg.push(block, Statement {
|
this.cfg.push(block, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::StorageLive(result.clone())
|
kind: StatementKind::StorageLive(result)
|
||||||
});
|
});
|
||||||
if let Some(scope) = scope {
|
if let Some(scope) = scope {
|
||||||
// schedule a shallow free of that memory, lest we unwind:
|
// schedule a shallow free of that memory, lest we unwind:
|
||||||
this.schedule_drop(expr_span, scope, &result, value.ty);
|
this.schedule_drop(expr_span, scope, &Lvalue::Local(result), value.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// malloc some memory of suitable type (thus far, uninitialized):
|
// malloc some memory of suitable type (thus far, uninitialized):
|
||||||
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
|
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
|
||||||
this.cfg.push_assign(block, source_info, &result, box_);
|
this.cfg.push_assign(block, source_info, &Lvalue::Local(result), box_);
|
||||||
|
|
||||||
// initialize the box contents:
|
// initialize the box contents:
|
||||||
unpack!(block = this.into(&result.clone().deref(), block, value));
|
unpack!(block = this.into(&Lvalue::Local(result).deref(), block, value));
|
||||||
block.and(Rvalue::Use(Operand::Consume(result)))
|
block.and(Rvalue::Use(Operand::Consume(Lvalue::Local(result))))
|
||||||
}
|
}
|
||||||
ExprKind::Cast { source } => {
|
ExprKind::Cast { source } => {
|
||||||
let source = this.hir.mirror(source);
|
let source = this.hir.mirror(source);
|
||||||
|
@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: M)
|
expr: M)
|
||||||
-> BlockAnd<Lvalue<'tcx>>
|
-> BlockAnd<Local>
|
||||||
where M: Mirror<'tcx, Output = Expr<'tcx>>
|
where M: Mirror<'tcx, Output = Expr<'tcx>>
|
||||||
{
|
{
|
||||||
let expr = self.hir.mirror(expr);
|
let expr = self.hir.mirror(expr);
|
||||||
@ -34,7 +34,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
mut block: BasicBlock,
|
mut block: BasicBlock,
|
||||||
temp_lifetime: Option<region::Scope>,
|
temp_lifetime: Option<region::Scope>,
|
||||||
expr: Expr<'tcx>)
|
expr: Expr<'tcx>)
|
||||||
-> BlockAnd<Lvalue<'tcx>> {
|
-> BlockAnd<Local> {
|
||||||
debug!("expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?})",
|
debug!("expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?})",
|
||||||
block, temp_lifetime, expr);
|
block, temp_lifetime, expr);
|
||||||
let this = self;
|
let this = self;
|
||||||
@ -47,13 +47,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let expr_ty = expr.ty.clone();
|
let expr_ty = expr.ty;
|
||||||
let temp = this.temp(expr_ty.clone(), expr_span);
|
let temp = this.local_decls.push(LocalDecl::new_temp(expr_ty, expr_span));
|
||||||
|
|
||||||
if !expr_ty.is_never() {
|
if !expr_ty.is_never() {
|
||||||
this.cfg.push(block, Statement {
|
this.cfg.push(block, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::StorageLive(temp.clone())
|
kind: StatementKind::StorageLive(temp)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,10 +68,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
Category::Lvalue => {
|
Category::Lvalue => {
|
||||||
let lvalue = unpack!(block = this.as_lvalue(block, expr));
|
let lvalue = unpack!(block = this.as_lvalue(block, expr));
|
||||||
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
|
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
|
||||||
this.cfg.push_assign(block, source_info, &temp, rvalue);
|
this.cfg.push_assign(block, source_info, &Lvalue::Local(temp), rvalue);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
unpack!(block = this.into(&temp, block, expr));
|
unpack!(block = this.into(&Lvalue::Local(temp), block, expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
// anything because no values with a destructor can be created in
|
// anything because no values with a destructor can be created in
|
||||||
// a constant at this time, even if the type may need dropping.
|
// a constant at this time, even if the type may need dropping.
|
||||||
if let Some(temp_lifetime) = temp_lifetime {
|
if let Some(temp_lifetime) = temp_lifetime {
|
||||||
this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty);
|
this.schedule_drop(expr_span, temp_lifetime, &Lvalue::Local(temp), expr_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
block.and(temp)
|
block.and(temp)
|
||||||
|
@ -229,7 +229,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
let topmost_scope = this.topmost_scope();
|
let topmost_scope = this.topmost_scope();
|
||||||
let ptr = unpack!(block = this.as_temp(block, Some(topmost_scope), ptr));
|
let ptr = unpack!(block = this.as_temp(block, Some(topmost_scope), ptr));
|
||||||
this.into(&ptr.deref(), block, val)
|
this.into(&Lvalue::Local(ptr).deref(), block, val)
|
||||||
} else {
|
} else {
|
||||||
let args: Vec<_> =
|
let args: Vec<_> =
|
||||||
args.into_iter()
|
args.into_iter()
|
||||||
|
@ -194,7 +194,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
let source_info = self.source_info(span);
|
let source_info = self.source_info(span);
|
||||||
self.cfg.push(block, Statement {
|
self.cfg.push(block, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::StorageLive(Lvalue::Local(local_id))
|
kind: StatementKind::StorageLive(local_id)
|
||||||
});
|
});
|
||||||
Lvalue::Local(local_id)
|
Lvalue::Local(local_id)
|
||||||
}
|
}
|
||||||
|
@ -822,7 +822,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
|
|||||||
Lvalue::Local(index) if index.index() > arg_count => {
|
Lvalue::Local(index) if index.index() > arg_count => {
|
||||||
cfg.push(block, Statement {
|
cfg.push(block, Statement {
|
||||||
source_info,
|
source_info,
|
||||||
kind: StatementKind::StorageDead(drop_data.location.clone())
|
kind: StatementKind::StorageDead(index)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => continue
|
_ => continue
|
||||||
|
@ -21,8 +21,7 @@
|
|||||||
//! `a[x]` would still overlap them both. But that is not this
|
//! `a[x]` would still overlap them both. But that is not this
|
||||||
//! representation does today.)
|
//! representation does today.)
|
||||||
|
|
||||||
use rustc::mir::LvalueElem;
|
use rustc::mir::{Local, LvalueElem, Operand, ProjectionElem};
|
||||||
use rustc::mir::{Operand, ProjectionElem};
|
|
||||||
use rustc::ty::Ty;
|
use rustc::ty::Ty;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
@ -40,6 +39,10 @@ impl<'tcx> Lift for Operand<'tcx> {
|
|||||||
type Abstract = AbstractOperand;
|
type Abstract = AbstractOperand;
|
||||||
fn lift(&self) -> Self::Abstract { AbstractOperand }
|
fn lift(&self) -> Self::Abstract { AbstractOperand }
|
||||||
}
|
}
|
||||||
|
impl Lift for Local {
|
||||||
|
type Abstract = AbstractOperand;
|
||||||
|
fn lift(&self) -> Self::Abstract { AbstractOperand }
|
||||||
|
}
|
||||||
impl<'tcx> Lift for Ty<'tcx> {
|
impl<'tcx> Lift for Ty<'tcx> {
|
||||||
type Abstract = AbstractType;
|
type Abstract = AbstractType;
|
||||||
fn lift(&self) -> Self::Abstract { AbstractType }
|
fn lift(&self) -> Self::Abstract { AbstractType }
|
||||||
|
@ -479,9 +479,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
|
|
||||||
fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
|
fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
let span = self.span;
|
||||||
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
|
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
|
||||||
|
|
||||||
let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
|
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
|
||||||
let end = self.make_lvalue(Mutability::Not, tcx.types.usize);
|
let end = self.make_lvalue(Mutability::Not, tcx.types.usize);
|
||||||
let ret = self.make_lvalue(Mutability::Mut, tcx.mk_array(ty, len));
|
let ret = self.make_lvalue(Mutability::Mut, tcx.mk_array(ty, len));
|
||||||
|
|
||||||
@ -492,7 +493,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
let inits = vec![
|
let inits = vec![
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
beg.clone(),
|
Lvalue::Local(beg),
|
||||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
@ -510,19 +511,19 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
// BB #3;
|
// BB #3;
|
||||||
// }
|
// }
|
||||||
// BB #4;
|
// BB #4;
|
||||||
self.loop_header(beg.clone(), end, BasicBlock::new(2), BasicBlock::new(4), false);
|
self.loop_header(Lvalue::Local(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
|
||||||
|
|
||||||
// BB #2
|
// BB #2
|
||||||
// `let cloned = Clone::clone(rcvr[beg])`;
|
// `let cloned = Clone::clone(rcvr[beg])`;
|
||||||
// Goto #3 if ok, #5 if unwinding happens.
|
// Goto #3 if ok, #5 if unwinding happens.
|
||||||
let rcvr_field = rcvr.clone().index(Operand::Consume(beg.clone()));
|
let rcvr_field = rcvr.clone().index(beg);
|
||||||
let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
|
let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
|
||||||
|
|
||||||
// BB #3
|
// BB #3
|
||||||
// `ret[beg] = cloned;`
|
// `ret[beg] = cloned;`
|
||||||
// `beg = beg + 1;`
|
// `beg = beg + 1;`
|
||||||
// `goto #1`;
|
// `goto #1`;
|
||||||
let ret_field = ret.clone().index(Operand::Consume(beg.clone()));
|
let ret_field = ret.clone().index(beg);
|
||||||
let statements = vec![
|
let statements = vec![
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
@ -532,10 +533,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
),
|
),
|
||||||
self.make_statement(
|
self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
beg.clone(),
|
Lvalue::Local(beg),
|
||||||
Rvalue::BinaryOp(
|
Rvalue::BinaryOp(
|
||||||
BinOp::Add,
|
BinOp::Add,
|
||||||
Operand::Consume(beg.clone()),
|
Operand::Consume(Lvalue::Local(beg)),
|
||||||
Operand::Constant(self.make_usize(1))
|
Operand::Constant(self.make_usize(1))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -558,10 +559,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
// `let mut beg = 0;`
|
// `let mut beg = 0;`
|
||||||
// goto #6;
|
// goto #6;
|
||||||
let end = beg;
|
let end = beg;
|
||||||
let beg = self.make_lvalue(Mutability::Mut, tcx.types.usize);
|
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
|
||||||
let init = self.make_statement(
|
let init = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
beg.clone(),
|
Lvalue::Local(beg),
|
||||||
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
Rvalue::Use(Operand::Constant(self.make_usize(0)))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -572,12 +573,13 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
// BB #8;
|
// BB #8;
|
||||||
// }
|
// }
|
||||||
// BB #9;
|
// BB #9;
|
||||||
self.loop_header(beg.clone(), end, BasicBlock::new(7), BasicBlock::new(9), true);
|
self.loop_header(Lvalue::Local(beg), Lvalue::Local(end),
|
||||||
|
BasicBlock::new(7), BasicBlock::new(9), true);
|
||||||
|
|
||||||
// BB #7 (cleanup)
|
// BB #7 (cleanup)
|
||||||
// `drop(ret[beg])`;
|
// `drop(ret[beg])`;
|
||||||
self.block(vec![], TerminatorKind::Drop {
|
self.block(vec![], TerminatorKind::Drop {
|
||||||
location: ret.index(Operand::Consume(beg.clone())),
|
location: ret.index(beg),
|
||||||
target: BasicBlock::new(8),
|
target: BasicBlock::new(8),
|
||||||
unwind: None,
|
unwind: None,
|
||||||
}, true);
|
}, true);
|
||||||
@ -587,10 +589,10 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||||||
// `goto #6;`
|
// `goto #6;`
|
||||||
let statement = self.make_statement(
|
let statement = self.make_statement(
|
||||||
StatementKind::Assign(
|
StatementKind::Assign(
|
||||||
beg.clone(),
|
Lvalue::Local(beg),
|
||||||
Rvalue::BinaryOp(
|
Rvalue::BinaryOp(
|
||||||
BinOp::Add,
|
BinOp::Add,
|
||||||
Operand::Consume(beg.clone()),
|
Operand::Consume(Lvalue::Local(beg)),
|
||||||
Operand::Constant(self.make_usize(1))
|
Operand::Constant(self.make_usize(1))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -236,8 +236,7 @@ impl<'tcx> Action<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replace all uses of the destination local with the source local.
|
// Replace all uses of the destination local with the source local.
|
||||||
let src_lvalue = Lvalue::Local(src_local);
|
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_local);
|
||||||
def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue);
|
|
||||||
|
|
||||||
// Finally, zap the now-useless assignment instruction.
|
// Finally, zap the now-useless assignment instruction.
|
||||||
debug!(" Deleting assignment");
|
debug!(" Deleting assignment");
|
||||||
|
@ -88,7 +88,9 @@ struct RenameLocalVisitor {
|
|||||||
|
|
||||||
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
||||||
fn visit_local(&mut self,
|
fn visit_local(&mut self,
|
||||||
local: &mut Local) {
|
local: &mut Local,
|
||||||
|
_: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
if *local == self.from {
|
if *local == self.from {
|
||||||
*local = self.to;
|
*local = self.to;
|
||||||
}
|
}
|
||||||
@ -98,6 +100,13 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor {
|
|||||||
struct DerefArgVisitor;
|
struct DerefArgVisitor;
|
||||||
|
|
||||||
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor {
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
local: &mut Local,
|
||||||
|
_: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
|
assert_ne!(*local, self_arg());
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
@ -177,6 +186,13 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
local: &mut Local,
|
||||||
|
_: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
|
assert_eq!(self.remap.get(local), None);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
@ -197,12 +213,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||||||
// Remove StorageLive and StorageDead statements for remapped locals
|
// Remove StorageLive and StorageDead statements for remapped locals
|
||||||
data.retain_statements(|s| {
|
data.retain_statements(|s| {
|
||||||
match s.kind {
|
match s.kind {
|
||||||
StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => {
|
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
|
||||||
if let Lvalue::Local(l) = *l {
|
!self.remap.contains_key(&l)
|
||||||
!self.remap.contains_key(&l)
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
|
@ -589,16 +589,6 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_local(&self, local: Local) -> Option<Local> {
|
|
||||||
let idx = local.index();
|
|
||||||
if idx < (self.args.len() + 1) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let idx = idx - (self.args.len() + 1);
|
|
||||||
let local = Local::new(idx);
|
|
||||||
self.local_map.get(local).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn arg_index(&self, arg: Local) -> Option<usize> {
|
fn arg_index(&self, arg: Local) -> Option<usize> {
|
||||||
let idx = arg.index();
|
let idx = arg.index();
|
||||||
if idx > 0 && idx <= self.args.len() {
|
if idx > 0 && idx <= self.args.len() {
|
||||||
@ -610,32 +600,35 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
local: &mut Local,
|
||||||
|
_ctxt: LvalueContext<'tcx>,
|
||||||
|
_location: Location) {
|
||||||
|
if *local == RETURN_POINTER {
|
||||||
|
match self.destination {
|
||||||
|
Lvalue::Local(l) => *local = l,
|
||||||
|
ref lval => bug!("Return lvalue is {:?}, not local", lval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let idx = local.index() - 1;
|
||||||
|
if idx < self.args.len() {
|
||||||
|
match self.args[idx] {
|
||||||
|
Operand::Consume(Lvalue::Local(l)) => *local = l,
|
||||||
|
ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*local = self.local_map[Local::new(idx - self.args.len())];
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
lvalue: &mut Lvalue<'tcx>,
|
||||||
_ctxt: LvalueContext<'tcx>,
|
_ctxt: LvalueContext<'tcx>,
|
||||||
_location: Location) {
|
_location: Location) {
|
||||||
if let Lvalue::Local(ref mut local) = *lvalue {
|
if let Lvalue::Local(RETURN_POINTER) = *lvalue {
|
||||||
if let Some(l) = self.update_local(*local) {
|
// Return pointer; update the lvalue itself
|
||||||
// Temp or Var; update the local reference
|
*lvalue = self.destination.clone();
|
||||||
*local = l;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
|
||||||
if local == RETURN_POINTER {
|
|
||||||
// Return pointer; update the lvalue itself
|
|
||||||
*lvalue = self.destination.clone();
|
|
||||||
} else if local.index() < (self.args.len() + 1) {
|
|
||||||
// Argument, once again update the the lvalue itself
|
|
||||||
let idx = local.index() - 1;
|
|
||||||
if let Operand::Consume(ref lval) = self.args[idx] {
|
|
||||||
*lvalue = lval.clone();
|
|
||||||
} else {
|
|
||||||
bug!("Arg operand `{:?}` is not an Lvalue use.", idx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.super_lvalue(lvalue, _ctxt, _location)
|
self.super_lvalue(lvalue, _ctxt, _location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,52 +83,49 @@ struct TempCollector<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&index: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
self.super_lvalue(lvalue, context, location);
|
// We're only interested in temporaries
|
||||||
if let Lvalue::Local(index) = *lvalue {
|
if self.mir.local_kind(index) != LocalKind::Temp {
|
||||||
// We're only interested in temporaries
|
return;
|
||||||
if self.mir.local_kind(index) != LocalKind::Temp {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore drops, if the temp gets promoted,
|
// Ignore drops, if the temp gets promoted,
|
||||||
// then it's constant and thus drop is noop.
|
// then it's constant and thus drop is noop.
|
||||||
// Storage live ranges are also irrelevant.
|
// Storage live ranges are also irrelevant.
|
||||||
if context.is_drop() || context.is_storage_marker() {
|
if context.is_drop() || context.is_storage_marker() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let temp = &mut self.temps[index];
|
let temp = &mut self.temps[index];
|
||||||
if *temp == TempState::Undefined {
|
if *temp == TempState::Undefined {
|
||||||
match context {
|
match context {
|
||||||
LvalueContext::Store |
|
LvalueContext::Store |
|
||||||
LvalueContext::Call => {
|
LvalueContext::Call => {
|
||||||
*temp = TempState::Defined {
|
*temp = TempState::Defined {
|
||||||
location,
|
location,
|
||||||
uses: 0
|
uses: 0
|
||||||
};
|
};
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => { /* mark as unpromotable below */ }
|
|
||||||
}
|
|
||||||
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
|
||||||
// We always allow borrows, even mutable ones, as we need
|
|
||||||
// to promote mutable borrows of some ZSTs e.g. `&mut []`.
|
|
||||||
let allowed_use = match context {
|
|
||||||
LvalueContext::Borrow {..} => true,
|
|
||||||
_ => context.is_nonmutating_use()
|
|
||||||
};
|
|
||||||
if allowed_use {
|
|
||||||
*uses += 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* mark as unpromotable below */
|
_ => { /* mark as unpromotable below */ }
|
||||||
}
|
}
|
||||||
*temp = TempState::Unpromotable;
|
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
||||||
|
// We always allow borrows, even mutable ones, as we need
|
||||||
|
// to promote mutable borrows of some ZSTs e.g. `&mut []`.
|
||||||
|
let allowed_use = match context {
|
||||||
|
LvalueContext::Borrow {..} => true,
|
||||||
|
_ => context.is_nonmutating_use()
|
||||||
|
};
|
||||||
|
if allowed_use {
|
||||||
|
*uses += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* mark as unpromotable below */
|
||||||
}
|
}
|
||||||
|
*temp = TempState::Unpromotable;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_source_info(&mut self, source_info: &SourceInfo) {
|
fn visit_source_info(&mut self, source_info: &SourceInfo) {
|
||||||
@ -326,16 +323,13 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||||||
|
|
||||||
/// Replaces all temporaries with their promoted counterparts.
|
/// Replaces all temporaries with their promoted counterparts.
|
||||||
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
local: &mut Local,
|
||||||
context: LvalueContext<'tcx>,
|
_: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
_: Location) {
|
||||||
if let Lvalue::Local(ref mut temp) = *lvalue {
|
if self.source.local_kind(*local) == LocalKind::Temp {
|
||||||
if self.source.local_kind(*temp) == LocalKind::Temp {
|
*local = self.promote_temp(*local);
|
||||||
*temp = self.promote_temp(*temp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.super_lvalue(lvalue, context, location);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,8 +406,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
|
|||||||
block.statements.retain(|statement| {
|
block.statements.retain(|statement| {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::Assign(Lvalue::Local(index), _) |
|
StatementKind::Assign(Lvalue::Local(index), _) |
|
||||||
StatementKind::StorageLive(Lvalue::Local(index)) |
|
StatementKind::StorageLive(index) |
|
||||||
StatementKind::StorageDead(Lvalue::Local(index)) => {
|
StatementKind::StorageDead(index) => {
|
||||||
!promoted(index)
|
!promoted(index)
|
||||||
}
|
}
|
||||||
_ => true
|
_ => true
|
||||||
|
@ -499,33 +499,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
|
|||||||
/// For functions (constant or not), it also records
|
/// For functions (constant or not), it also records
|
||||||
/// candidates for promotion in promotion_candidates.
|
/// candidates for promotion in promotion_candidates.
|
||||||
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
&local: &Local,
|
||||||
|
_: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
|
match self.mir.local_kind(local) {
|
||||||
|
LocalKind::ReturnPointer => {
|
||||||
|
self.not_const();
|
||||||
|
}
|
||||||
|
LocalKind::Arg => {
|
||||||
|
self.add(Qualif::FN_ARGUMENT);
|
||||||
|
}
|
||||||
|
LocalKind::Var => {
|
||||||
|
self.add(Qualif::NOT_CONST);
|
||||||
|
}
|
||||||
|
LocalKind::Temp => {
|
||||||
|
if !self.temp_promotion_state[local].is_promotable() {
|
||||||
|
self.add(Qualif::NOT_PROMOTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(qualif) = self.temp_qualif[local] {
|
||||||
|
self.add(qualif);
|
||||||
|
} else {
|
||||||
|
self.not_const();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_lvalue(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
lvalue: &Lvalue<'tcx>,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
match *lvalue {
|
match *lvalue {
|
||||||
Lvalue::Local(local) => match self.mir.local_kind(local) {
|
Lvalue::Local(ref local) => self.visit_local(local, context, location),
|
||||||
LocalKind::ReturnPointer => {
|
|
||||||
self.not_const();
|
|
||||||
}
|
|
||||||
LocalKind::Arg => {
|
|
||||||
self.add(Qualif::FN_ARGUMENT);
|
|
||||||
}
|
|
||||||
LocalKind::Var => {
|
|
||||||
self.add(Qualif::NOT_CONST);
|
|
||||||
}
|
|
||||||
LocalKind::Temp => {
|
|
||||||
if !self.temp_promotion_state[local].is_promotable() {
|
|
||||||
self.add(Qualif::NOT_PROMOTABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(qualif) = self.temp_qualif[local] {
|
|
||||||
self.add(qualif);
|
|
||||||
} else {
|
|
||||||
self.not_const();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Lvalue::Static(ref global) => {
|
Lvalue::Static(ref global) => {
|
||||||
self.add(Qualif::STATIC);
|
self.add(Qualif::STATIC);
|
||||||
|
|
||||||
@ -1101,7 +1108,7 @@ impl MirPass for QualifyAndPromoteConstants {
|
|||||||
for block in mir.basic_blocks_mut() {
|
for block in mir.basic_blocks_mut() {
|
||||||
block.statements.retain(|statement| {
|
block.statements.retain(|statement| {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::StorageDead(Lvalue::Local(index)) => {
|
StatementKind::StorageDead(index) => {
|
||||||
!promoted_temps.contains(&index)
|
!promoted_temps.contains(&index)
|
||||||
}
|
}
|
||||||
_ => true
|
_ => true
|
||||||
|
@ -352,15 +352,11 @@ struct DeclMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for DeclMarker {
|
impl<'tcx> Visitor<'tcx> for DeclMarker {
|
||||||
fn visit_lvalue(&mut self, lval: &Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
|
fn visit_local(&mut self, local: &Local, ctx: LvalueContext<'tcx>, _: Location) {
|
||||||
if ctx == LvalueContext::StorageLive || ctx == LvalueContext::StorageDead {
|
// ignore these altogether, they get removed along with their otherwise unused decls.
|
||||||
// ignore these altogether, they get removed along with their otherwise unused decls.
|
if ctx != LvalueContext::StorageLive && ctx != LvalueContext::StorageDead {
|
||||||
return;
|
self.locals.insert(local.index());
|
||||||
}
|
}
|
||||||
if let Lvalue::Local(ref v) = *lval {
|
|
||||||
self.locals.insert(v.index());
|
|
||||||
}
|
|
||||||
self.super_lvalue(lval, ctx, loc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,22 +369,15 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater {
|
|||||||
// Remove unnecessary StorageLive and StorageDead annotations.
|
// Remove unnecessary StorageLive and StorageDead annotations.
|
||||||
data.statements.retain(|stmt| {
|
data.statements.retain(|stmt| {
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StatementKind::StorageLive(ref lval) | StatementKind::StorageDead(ref lval) => {
|
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
|
||||||
match *lval {
|
self.map[l.index()] != !0
|
||||||
Lvalue::Local(l) => self.map[l.index()] != !0,
|
|
||||||
_ => true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.super_basic_block_data(block, data);
|
self.super_basic_block_data(block, data);
|
||||||
}
|
}
|
||||||
fn visit_lvalue(&mut self, lval: &mut Lvalue<'tcx>, ctx: LvalueContext<'tcx>, loc: Location) {
|
fn visit_local(&mut self, l: &mut Local, _: LvalueContext<'tcx>, _: Location) {
|
||||||
match *lval {
|
*l = Local::new(self.map[l.index()]);
|
||||||
Lvalue::Local(ref mut l) => *l = Local::new(self.map[l.index()]),
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
self.super_lvalue(lval, ctx, loc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||||||
base: LvalueTy<'tcx>,
|
base: LvalueTy<'tcx>,
|
||||||
pi: &LvalueElem<'tcx>,
|
pi: &LvalueElem<'tcx>,
|
||||||
lvalue: &Lvalue<'tcx>,
|
lvalue: &Lvalue<'tcx>,
|
||||||
location: Location)
|
_: Location)
|
||||||
-> LvalueTy<'tcx> {
|
-> LvalueTy<'tcx> {
|
||||||
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
|
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
@ -181,9 +181,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProjectionElem::Index(ref i) => {
|
ProjectionElem::Index(i) => {
|
||||||
self.visit_operand(i, location);
|
let index_ty = Lvalue::Local(i).ty(self.mir, tcx).to_ty(tcx);
|
||||||
let index_ty = i.ty(self.mir, tcx);
|
|
||||||
if index_ty != tcx.types.usize {
|
if index_ty != tcx.types.usize {
|
||||||
LvalueTy::Ty {
|
LvalueTy::Ty {
|
||||||
ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
|
ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i)
|
||||||
@ -421,15 +420,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
variant_index);
|
variant_index);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
StatementKind::StorageLive(ref lv) |
|
StatementKind::StorageLive(_) |
|
||||||
StatementKind::StorageDead(ref lv) => {
|
StatementKind::StorageDead(_) |
|
||||||
match *lv {
|
|
||||||
Lvalue::Local(_) => {}
|
|
||||||
_ => {
|
|
||||||
span_mirbug!(self, stmt, "bad lvalue: expected local");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StatementKind::InlineAsm { .. } |
|
StatementKind::InlineAsm { .. } |
|
||||||
StatementKind::EndRegion(_) |
|
StatementKind::EndRegion(_) |
|
||||||
StatementKind::Validate(..) |
|
StatementKind::Validate(..) |
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
//! Def-use analysis.
|
//! Def-use analysis.
|
||||||
|
|
||||||
use rustc::mir::{Local, Location, Lvalue, Mir};
|
use rustc::mir::{Local, Location, Mir};
|
||||||
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
|
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@ -51,7 +51,7 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
|
fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
|
||||||
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
|
where F: for<'a> FnMut(&'a mut Local,
|
||||||
LvalueContext<'tcx>,
|
LvalueContext<'tcx>,
|
||||||
Location) {
|
Location) {
|
||||||
for lvalue_use in &self.info[local].defs_and_uses {
|
for lvalue_use in &self.info[local].defs_and_uses {
|
||||||
@ -65,8 +65,8 @@ impl<'tcx> DefUseAnalysis<'tcx> {
|
|||||||
pub fn replace_all_defs_and_uses_with(&self,
|
pub fn replace_all_defs_and_uses_with(&self,
|
||||||
local: Local,
|
local: Local,
|
||||||
mir: &mut Mir<'tcx>,
|
mir: &mut Mir<'tcx>,
|
||||||
new_lvalue: Lvalue<'tcx>) {
|
new_local: Local) {
|
||||||
self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
|
self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,30 +74,15 @@ struct DefUseFinder<'tcx> {
|
|||||||
info: IndexVec<Local, Info<'tcx>>,
|
info: IndexVec<Local, Info<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DefUseFinder<'tcx> {
|
|
||||||
fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
|
|
||||||
let info = &mut self.info;
|
|
||||||
|
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
|
||||||
Some(&mut info[local])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
|
impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&local: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
|
self.info[local].defs_and_uses.push(Use {
|
||||||
info.defs_and_uses.push(Use {
|
context,
|
||||||
context,
|
location,
|
||||||
location,
|
});
|
||||||
})
|
|
||||||
}
|
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +119,7 @@ struct MutateUseVisitor<'tcx, F> {
|
|||||||
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
||||||
fn new(query: Local, callback: F, _: &Mir<'tcx>)
|
fn new(query: Local, callback: F, _: &Mir<'tcx>)
|
||||||
-> MutateUseVisitor<'tcx, F>
|
-> MutateUseVisitor<'tcx, F>
|
||||||
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
|
where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
|
||||||
MutateUseVisitor {
|
MutateUseVisitor {
|
||||||
query,
|
query,
|
||||||
callback,
|
callback,
|
||||||
@ -144,16 +129,13 @@ impl<'tcx, F> MutateUseVisitor<'tcx, F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
|
impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
|
||||||
where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
|
where F: for<'a> FnMut(&'a mut Local, LvalueContext<'tcx>, Location) {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &mut Lvalue<'tcx>,
|
local: &mut Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
if *local == self.query {
|
||||||
if local == self.query {
|
(self.callback)(local, context, location)
|
||||||
(self.callback)(lvalue, context, location)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -565,7 +565,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
/// drop(ptr)
|
/// drop(ptr)
|
||||||
fn drop_loop(&mut self,
|
fn drop_loop(&mut self,
|
||||||
succ: BasicBlock,
|
succ: BasicBlock,
|
||||||
cur: &Lvalue<'tcx>,
|
cur: Local,
|
||||||
length_or_end: &Lvalue<'tcx>,
|
length_or_end: &Lvalue<'tcx>,
|
||||||
ety: Ty<'tcx>,
|
ety: Ty<'tcx>,
|
||||||
unwind: Unwind,
|
unwind: Unwind,
|
||||||
@ -584,20 +584,20 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
|
|
||||||
let one = self.constant_usize(1);
|
let one = self.constant_usize(1);
|
||||||
let (ptr_next, cur_next) = if ptr_based {
|
let (ptr_next, cur_next) = if ptr_based {
|
||||||
(Rvalue::Use(use_(cur)),
|
(Rvalue::Use(use_(&Lvalue::Local(cur))),
|
||||||
Rvalue::BinaryOp(BinOp::Offset, use_(cur), one))
|
Rvalue::BinaryOp(BinOp::Offset, use_(&Lvalue::Local(cur)), one))
|
||||||
} else {
|
} else {
|
||||||
(Rvalue::Ref(
|
(Rvalue::Ref(
|
||||||
tcx.types.re_erased,
|
tcx.types.re_erased,
|
||||||
BorrowKind::Mut,
|
BorrowKind::Mut,
|
||||||
self.lvalue.clone().index(use_(cur))),
|
self.lvalue.clone().index(cur)),
|
||||||
Rvalue::BinaryOp(BinOp::Add, use_(cur), one))
|
Rvalue::BinaryOp(BinOp::Add, use_(&Lvalue::Local(cur)), one))
|
||||||
};
|
};
|
||||||
|
|
||||||
let drop_block = BasicBlockData {
|
let drop_block = BasicBlockData {
|
||||||
statements: vec![
|
statements: vec![
|
||||||
self.assign(ptr, ptr_next),
|
self.assign(ptr, ptr_next),
|
||||||
self.assign(cur, cur_next)
|
self.assign(&Lvalue::Local(cur), cur_next)
|
||||||
],
|
],
|
||||||
is_cleanup: unwind.is_cleanup(),
|
is_cleanup: unwind.is_cleanup(),
|
||||||
terminator: Some(Terminator {
|
terminator: Some(Terminator {
|
||||||
@ -611,7 +611,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
let loop_block = BasicBlockData {
|
let loop_block = BasicBlockData {
|
||||||
statements: vec![
|
statements: vec![
|
||||||
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
|
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
|
||||||
use_(cur),
|
use_(&Lvalue::Local(cur)),
|
||||||
use_(length_or_end)))
|
use_(length_or_end)))
|
||||||
],
|
],
|
||||||
is_cleanup: unwind.is_cleanup(),
|
is_cleanup: unwind.is_cleanup(),
|
||||||
@ -678,7 +678,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
tcx.types.usize
|
tcx.types.usize
|
||||||
};
|
};
|
||||||
|
|
||||||
let cur = Lvalue::Local(self.new_temp(iter_ty));
|
let cur = self.new_temp(iter_ty);
|
||||||
let length = Lvalue::Local(self.new_temp(tcx.types.usize));
|
let length = Lvalue::Local(self.new_temp(tcx.types.usize));
|
||||||
let length_or_end = if ptr_based {
|
let length_or_end = if ptr_based {
|
||||||
Lvalue::Local(self.new_temp(iter_ty))
|
Lvalue::Local(self.new_temp(iter_ty))
|
||||||
@ -688,7 +688,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
|
|
||||||
let unwind = self.unwind.map(|unwind| {
|
let unwind = self.unwind.map(|unwind| {
|
||||||
self.drop_loop(unwind,
|
self.drop_loop(unwind,
|
||||||
&cur,
|
cur,
|
||||||
&length_or_end,
|
&length_or_end,
|
||||||
ety,
|
ety,
|
||||||
Unwind::InCleanup,
|
Unwind::InCleanup,
|
||||||
@ -698,12 +698,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||||||
let succ = self.succ; // FIXME(#6393)
|
let succ = self.succ; // FIXME(#6393)
|
||||||
let loop_block = self.drop_loop(
|
let loop_block = self.drop_loop(
|
||||||
succ,
|
succ,
|
||||||
&cur,
|
cur,
|
||||||
&length_or_end,
|
&length_or_end,
|
||||||
ety,
|
ety,
|
||||||
unwind,
|
unwind,
|
||||||
ptr_based);
|
ptr_based);
|
||||||
|
|
||||||
|
let cur = Lvalue::Local(cur);
|
||||||
let zero = self.constant_usize(0);
|
let zero = self.constant_usize(0);
|
||||||
let mut drop_block_stmts = vec![];
|
let mut drop_block_stmts = vec![];
|
||||||
drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.lvalue.clone())));
|
drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.lvalue.clone())));
|
||||||
|
@ -60,49 +60,45 @@ struct BlockInfoVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
|
impl<'tcx> Visitor<'tcx> for BlockInfoVisitor {
|
||||||
fn visit_lvalue(&mut self,
|
fn visit_local(&mut self,
|
||||||
lvalue: &Lvalue<'tcx>,
|
&local: &Local,
|
||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
_: Location) {
|
||||||
if let Lvalue::Local(local) = *lvalue {
|
match context {
|
||||||
match context {
|
LvalueContext::Store |
|
||||||
LvalueContext::Store |
|
|
||||||
|
|
||||||
// We let Call defined the result in both the success and unwind cases.
|
// We let Call defined the result in both the success and unwind cases.
|
||||||
// This may not be right.
|
// This may not be right.
|
||||||
LvalueContext::Call |
|
LvalueContext::Call |
|
||||||
|
|
||||||
// Storage live and storage dead aren't proper defines, but we can ignore
|
// Storage live and storage dead aren't proper defines, but we can ignore
|
||||||
// values that come before them.
|
// values that come before them.
|
||||||
LvalueContext::StorageLive |
|
LvalueContext::StorageLive |
|
||||||
LvalueContext::StorageDead => {
|
LvalueContext::StorageDead => {
|
||||||
self.defs.add(&local);
|
self.defs.add(&local);
|
||||||
}
|
}
|
||||||
LvalueContext::Projection(..) |
|
LvalueContext::Projection(..) |
|
||||||
|
|
||||||
// Borrows only consider their local used at the point of the borrow.
|
// Borrows only consider their local used at the point of the borrow.
|
||||||
// This won't affect the results since we use this analysis for generators
|
// This won't affect the results since we use this analysis for generators
|
||||||
// and we only care about the result at suspension points. Borrows cannot
|
// and we only care about the result at suspension points. Borrows cannot
|
||||||
// cross suspension points so this behavior is unproblematic.
|
// cross suspension points so this behavior is unproblematic.
|
||||||
LvalueContext::Borrow { .. } |
|
LvalueContext::Borrow { .. } |
|
||||||
|
|
||||||
LvalueContext::Inspect |
|
LvalueContext::Inspect |
|
||||||
LvalueContext::Consume |
|
LvalueContext::Consume |
|
||||||
LvalueContext::Validate |
|
LvalueContext::Validate |
|
||||||
|
|
||||||
// We consider drops to always be uses of locals.
|
// We consider drops to always be uses of locals.
|
||||||
// Drop eloboration should be run before this analysis otherwise
|
// Drop eloboration should be run before this analysis otherwise
|
||||||
// the results might be too pessimistic.
|
// the results might be too pessimistic.
|
||||||
LvalueContext::Drop => {
|
LvalueContext::Drop => {
|
||||||
// Ignore uses which are already defined in this block
|
// Ignore uses which are already defined in this block
|
||||||
if !self.pre_defs.contains(&local) {
|
if !self.pre_defs.contains(&local) {
|
||||||
self.uses.add(&local);
|
self.uses.add(&local);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.super_lvalue(lvalue, context, location)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,54 +134,22 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||||||
location: Location) {
|
location: Location) {
|
||||||
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
|
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
|
||||||
|
|
||||||
// Allow uses of projections of immediate pair fields.
|
|
||||||
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
||||||
if let mir::Lvalue::Local(_) = proj.base {
|
// Allow uses of projections of immediate pair fields.
|
||||||
let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
|
if let LvalueContext::Consume = context {
|
||||||
|
if let mir::Lvalue::Local(_) = proj.base {
|
||||||
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
|
|
||||||
if common::type_is_imm_pair(self.cx.ccx, ty) {
|
|
||||||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
if let mir::ProjectionElem::Field(..) = proj.elem {
|
||||||
if let LvalueContext::Consume = context {
|
let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
|
||||||
|
|
||||||
|
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
|
||||||
|
if common::type_is_imm_pair(self.cx.ccx, ty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let mir::Lvalue::Local(index) = *lvalue {
|
// A deref projection only reads the pointer, never needs the lvalue.
|
||||||
match context {
|
|
||||||
LvalueContext::Call => {
|
|
||||||
self.mark_assigned(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
LvalueContext::StorageLive |
|
|
||||||
LvalueContext::StorageDead |
|
|
||||||
LvalueContext::Validate |
|
|
||||||
LvalueContext::Inspect |
|
|
||||||
LvalueContext::Consume => {}
|
|
||||||
|
|
||||||
LvalueContext::Store |
|
|
||||||
LvalueContext::Borrow { .. } |
|
|
||||||
LvalueContext::Projection(..) => {
|
|
||||||
self.mark_as_lvalue(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
LvalueContext::Drop => {
|
|
||||||
let ty = lvalue.ty(self.cx.mir, self.cx.ccx.tcx());
|
|
||||||
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
|
|
||||||
|
|
||||||
// Only need the lvalue if we're actually dropping it.
|
|
||||||
if self.cx.ccx.shared().type_needs_drop(ty) {
|
|
||||||
self.mark_as_lvalue(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A deref projection only reads the pointer, never needs the lvalue.
|
|
||||||
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
|
||||||
if let mir::ProjectionElem::Deref = proj.elem {
|
if let mir::ProjectionElem::Deref = proj.elem {
|
||||||
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||||
}
|
}
|
||||||
@ -189,6 +157,39 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||||||
|
|
||||||
self.super_lvalue(lvalue, context, location);
|
self.super_lvalue(lvalue, context, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_local(&mut self,
|
||||||
|
&index: &mir::Local,
|
||||||
|
context: LvalueContext<'tcx>,
|
||||||
|
_: Location) {
|
||||||
|
match context {
|
||||||
|
LvalueContext::Call => {
|
||||||
|
self.mark_assigned(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
LvalueContext::StorageLive |
|
||||||
|
LvalueContext::StorageDead |
|
||||||
|
LvalueContext::Validate |
|
||||||
|
LvalueContext::Inspect |
|
||||||
|
LvalueContext::Consume => {}
|
||||||
|
|
||||||
|
LvalueContext::Store |
|
||||||
|
LvalueContext::Borrow { .. } |
|
||||||
|
LvalueContext::Projection(..) => {
|
||||||
|
self.mark_as_lvalue(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
LvalueContext::Drop => {
|
||||||
|
let ty = mir::Lvalue::Local(index).ty(self.cx.mir, self.cx.ccx.tcx());
|
||||||
|
let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
|
||||||
|
|
||||||
|
// Only need the lvalue if we're actually dropping it.
|
||||||
|
if self.cx.ccx.shared().type_needs_drop(ty) {
|
||||||
|
self.mark_as_lvalue(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -471,7 +471,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
(Base::Value(llprojected), llextra)
|
(Base::Value(llprojected), llextra)
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Index(ref index) => {
|
mir::ProjectionElem::Index(index) => {
|
||||||
|
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||||
let llindex = self.const_operand(index, span)?.llval;
|
let llindex = self.const_operand(index, span)?.llval;
|
||||||
|
|
||||||
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
||||||
|
@ -333,7 +333,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
(tr_base.trans_field_ptr(bcx, field.index()), llextra)
|
(tr_base.trans_field_ptr(bcx, field.index()), llextra)
|
||||||
}
|
}
|
||||||
mir::ProjectionElem::Index(ref index) => {
|
mir::ProjectionElem::Index(index) => {
|
||||||
|
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||||
let index = self.trans_operand(bcx, index);
|
let index = self.trans_operand(bcx, index);
|
||||||
let llindex = self.prepare_index(bcx, index.immediate());
|
let llindex = self.prepare_index(bcx, index.immediate());
|
||||||
((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
|
((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
|
||||||
|
@ -67,11 +67,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||||||
variant_index as u64);
|
variant_index as u64);
|
||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
mir::StatementKind::StorageLive(ref lvalue) => {
|
mir::StatementKind::StorageLive(local) => {
|
||||||
self.trans_storage_liveness(bcx, lvalue, base::Lifetime::Start)
|
self.trans_storage_liveness(bcx, local, base::Lifetime::Start)
|
||||||
}
|
}
|
||||||
mir::StatementKind::StorageDead(ref lvalue) => {
|
mir::StatementKind::StorageDead(local) => {
|
||||||
self.trans_storage_liveness(bcx, lvalue, base::Lifetime::End)
|
self.trans_storage_liveness(bcx, local, base::Lifetime::End)
|
||||||
}
|
}
|
||||||
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||||
let outputs = outputs.iter().map(|output| {
|
let outputs = outputs.iter().map(|output| {
|
||||||
@ -94,13 +94,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||||||
|
|
||||||
fn trans_storage_liveness(&self,
|
fn trans_storage_liveness(&self,
|
||||||
bcx: Builder<'a, 'tcx>,
|
bcx: Builder<'a, 'tcx>,
|
||||||
lvalue: &mir::Lvalue<'tcx>,
|
index: mir::Local,
|
||||||
intrinsic: base::Lifetime)
|
intrinsic: base::Lifetime)
|
||||||
-> Builder<'a, 'tcx> {
|
-> Builder<'a, 'tcx> {
|
||||||
if let mir::Lvalue::Local(index) = *lvalue {
|
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
|
||||||
if let LocalRef::Lvalue(tr_lval) = self.locals[index] {
|
intrinsic.call(&bcx, tr_lval.llval);
|
||||||
intrinsic.call(&bcx, tr_lval.llval);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bcx
|
bcx
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user