MIR: split Operand::Consume into Copy and Move.
This commit is contained in:
parent
73f5bab33f
commit
c42a118188
@ -420,7 +420,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) => {
|
||||
lvalue.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
lvalue.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
|
@ -1283,7 +1283,17 @@ pub struct VisibilityScopeData {
|
||||
/// being nested in one another.
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Operand<'tcx> {
|
||||
Consume(Lvalue<'tcx>),
|
||||
/// Copy: The value must be available for use afterwards.
|
||||
///
|
||||
/// This implies that the type of the lvalue must be `Copy`; this is true
|
||||
/// by construction during build, but also checked by the MIR type checker.
|
||||
Copy(Lvalue<'tcx>),
|
||||
/// Move: The value (including old borrows of it) will not be used again.
|
||||
///
|
||||
/// Safe for values of all types (modulo future developments towards `?Move`).
|
||||
/// Correct usage patterns are enforced by the borrow checker for safe code.
|
||||
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
|
||||
Move(Lvalue<'tcx>),
|
||||
Constant(Box<Constant<'tcx>>),
|
||||
}
|
||||
|
||||
@ -1292,7 +1302,8 @@ impl<'tcx> Debug for Operand<'tcx> {
|
||||
use self::Operand::*;
|
||||
match *self {
|
||||
Constant(ref a) => write!(fmt, "{:?}", a),
|
||||
Consume(ref lv) => write!(fmt, "{:?}", lv),
|
||||
Copy(ref lv) => write!(fmt, "{:?}", lv),
|
||||
Move(ref lv) => write!(fmt, "move {:?}", lv),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2089,14 +2100,16 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
||||
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
|
||||
Operand::Copy(ref lval) => Operand::Copy(lval.fold_with(folder)),
|
||||
Operand::Move(ref lval) => Operand::Move(lval.fold_with(folder)),
|
||||
Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
Operand::Consume(ref lval) => lval.visit_with(visitor),
|
||||
Operand::Copy(ref lval) |
|
||||
Operand::Move(ref lval) => lval.visit_with(visitor),
|
||||
Operand::Constant(ref c) => c.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,8 @@ impl<'tcx> Operand<'tcx> {
|
||||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
match self {
|
||||
&Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
|
||||
&Operand::Copy(ref l) |
|
||||
&Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
|
||||
&Operand::Constant(ref c) => c.ty,
|
||||
}
|
||||
}
|
||||
|
@ -611,8 +611,11 @@ macro_rules! make_mir_visitor {
|
||||
operand: & $($mutability)* Operand<'tcx>,
|
||||
location: Location) {
|
||||
match *operand {
|
||||
Operand::Consume(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Consume, location);
|
||||
Operand::Copy(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Copy, location);
|
||||
}
|
||||
Operand::Move(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Move, location);
|
||||
}
|
||||
Operand::Constant(ref $($mutability)* constant) => {
|
||||
self.visit_constant(constant, location);
|
||||
@ -679,7 +682,7 @@ macro_rules! make_mir_visitor {
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(ref $($mutability)* local) => {
|
||||
self.visit_local(local, LvalueContext::Consume, location);
|
||||
self.visit_local(local, LvalueContext::Copy, location);
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
@ -860,7 +863,8 @@ pub enum LvalueContext<'tcx> {
|
||||
Projection(Mutability),
|
||||
|
||||
// Consumed as part of an operand
|
||||
Consume,
|
||||
Copy,
|
||||
Move,
|
||||
|
||||
// Starting and ending a storage live range
|
||||
StorageLive,
|
||||
@ -913,7 +917,8 @@ impl<'tcx> LvalueContext<'tcx> {
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
|
||||
LvalueContext::Projection(Mutability::Not) |
|
||||
LvalueContext::Copy | LvalueContext::Move |
|
||||
LvalueContext::StorageLive | LvalueContext::StorageDead |
|
||||
LvalueContext::Validate => false,
|
||||
}
|
||||
@ -924,7 +929,8 @@ impl<'tcx> LvalueContext<'tcx> {
|
||||
match *self {
|
||||
LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
|
||||
LvalueContext::Projection(Mutability::Not) |
|
||||
LvalueContext::Copy | LvalueContext::Move => true,
|
||||
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
|
||||
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
|
||||
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |
|
||||
|
@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
|
||||
use rustc_data_structures::indexed_vec::{Idx};
|
||||
|
||||
use syntax::ast::{self};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use dataflow::{do_dataflow};
|
||||
use dataflow::{MoveDataParamEnv};
|
||||
@ -38,7 +38,6 @@ use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult, M
|
||||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
|
||||
use self::MutateMode::{JustWrite, WriteAndRead};
|
||||
use self::ConsumeKind::{Consume};
|
||||
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
@ -77,7 +76,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
let id = tcx.hir.as_local_node_id(def_id)
|
||||
.expect("do_mir_borrowck: non-local DefId");
|
||||
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx) {
|
||||
Ok(move_data) => move_data,
|
||||
Err((move_data, move_errors)) => {
|
||||
for move_error in move_errors {
|
||||
@ -264,14 +263,19 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
flow_state);
|
||||
}
|
||||
StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
|
||||
let context = ContextKind::InlineAsm.new(location);
|
||||
for (o, output) in asm.outputs.iter().zip(outputs) {
|
||||
if o.is_indirect {
|
||||
self.consume_lvalue(ContextKind::InlineAsm.new(location),
|
||||
Consume,
|
||||
(output, span),
|
||||
flow_state);
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoeded through MIR lvalue derefs instead.
|
||||
self.access_lvalue(context,
|
||||
(output, span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
flow_state);
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
(output, span), flow_state);
|
||||
} else {
|
||||
self.mutate_lvalue(ContextKind::InlineAsm.new(location),
|
||||
self.mutate_lvalue(context,
|
||||
(output, span),
|
||||
Deep,
|
||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||
@ -279,9 +283,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
}
|
||||
}
|
||||
for input in inputs {
|
||||
self.consume_operand(ContextKind::InlineAsm.new(location),
|
||||
Consume,
|
||||
(input, span), flow_state);
|
||||
self.consume_operand(context, (input, span), flow_state);
|
||||
}
|
||||
}
|
||||
StatementKind::EndRegion(ref _rgn) => {
|
||||
@ -314,13 +316,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
match term.kind {
|
||||
TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
|
||||
self.consume_operand(ContextKind::SwitchInt.new(loc),
|
||||
Consume,
|
||||
(discr, span), flow_state);
|
||||
}
|
||||
TerminatorKind::Drop { location: ref drop_lvalue, target: _, unwind: _ } => {
|
||||
self.consume_lvalue(ContextKind::Drop.new(loc),
|
||||
ConsumeKind::Drop,
|
||||
(drop_lvalue, span), flow_state);
|
||||
self.access_lvalue(ContextKind::Drop.new(loc),
|
||||
(drop_lvalue, span),
|
||||
(Deep, Write(WriteKind::StorageDeadOrDrop)),
|
||||
flow_state);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { location: ref drop_lvalue,
|
||||
value: ref new_value,
|
||||
@ -332,16 +334,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
JustWrite,
|
||||
flow_state);
|
||||
self.consume_operand(ContextKind::DropAndReplace.new(loc),
|
||||
ConsumeKind::Drop,
|
||||
(new_value, span), flow_state);
|
||||
}
|
||||
TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
|
||||
self.consume_operand(ContextKind::CallOperator.new(loc),
|
||||
Consume,
|
||||
(func, span), flow_state);
|
||||
for arg in args {
|
||||
self.consume_operand(ContextKind::CallOperand.new(loc),
|
||||
Consume,
|
||||
(arg, span), flow_state);
|
||||
}
|
||||
if let Some((ref dest, _/*bb*/)) = *destination {
|
||||
@ -354,15 +353,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
}
|
||||
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
||||
self.consume_operand(ContextKind::Assert.new(loc),
|
||||
Consume,
|
||||
(cond, span), flow_state);
|
||||
match *msg {
|
||||
AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
self.consume_operand(ContextKind::Assert.new(loc),
|
||||
Consume,
|
||||
(len, span), flow_state);
|
||||
self.consume_operand(ContextKind::Assert.new(loc),
|
||||
Consume,
|
||||
(index, span), flow_state);
|
||||
}
|
||||
AssertMessage::Math(_/*const_math_err*/) => {}
|
||||
@ -373,7 +369,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
|
||||
TerminatorKind::Yield { ref value, resume: _, drop: _} => {
|
||||
self.consume_operand(ContextKind::Yield.new(loc),
|
||||
Consume, (value, span), flow_state);
|
||||
(value, span), flow_state);
|
||||
}
|
||||
|
||||
TerminatorKind::Resume |
|
||||
@ -422,9 +418,6 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum MutateMode { JustWrite, WriteAndRead }
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum ConsumeKind { Drop, Consume }
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
enum Control { Continue, Break }
|
||||
|
||||
@ -648,7 +641,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
Rvalue::Repeat(ref operand, _) |
|
||||
Rvalue::UnaryOp(_/*un_op*/, ref operand) |
|
||||
Rvalue::Cast(_/*cast_kind*/, ref operand, _/*ty*/) => {
|
||||
self.consume_operand(context, Consume, (operand, span), flow_state)
|
||||
self.consume_operand(context, (operand, span), flow_state)
|
||||
}
|
||||
|
||||
Rvalue::Len(ref lvalue) |
|
||||
@ -666,8 +659,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, ref operand1, ref operand2) |
|
||||
Rvalue::CheckedBinaryOp(_bin_op, ref operand1, ref operand2) => {
|
||||
self.consume_operand(context, Consume, (operand1, span), flow_state);
|
||||
self.consume_operand(context, Consume, (operand2, span), flow_state);
|
||||
self.consume_operand(context, (operand1, span), flow_state);
|
||||
self.consume_operand(context, (operand2, span), flow_state);
|
||||
}
|
||||
|
||||
Rvalue::NullaryOp(_op, _ty) => {
|
||||
@ -680,7 +673,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
Rvalue::Aggregate(ref _aggregate_kind, ref operands) => {
|
||||
for operand in operands {
|
||||
self.consume_operand(context, Consume, (operand, span), flow_state);
|
||||
self.consume_operand(context, (operand, span), flow_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -688,64 +681,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
|
||||
fn consume_operand(&mut self,
|
||||
context: Context,
|
||||
consume_via_drop: ConsumeKind,
|
||||
(operand, span): (&Operand<'tcx>, Span),
|
||||
flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
|
||||
match *operand {
|
||||
Operand::Consume(ref lvalue) => {
|
||||
self.consume_lvalue(context, consume_via_drop, (lvalue, span), flow_state)
|
||||
Operand::Copy(ref lvalue) => {
|
||||
// copy of lvalue: check if this is "copy of frozen path"
|
||||
// (FIXME: see check_loans.rs)
|
||||
self.access_lvalue(context,
|
||||
(lvalue, span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
flow_state);
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
(lvalue, span), flow_state);
|
||||
}
|
||||
Operand::Move(ref lvalue) => {
|
||||
// move of lvalue: check if this is move of already borrowed path
|
||||
self.access_lvalue(context,
|
||||
(lvalue, span),
|
||||
(Deep, Write(WriteKind::Move)),
|
||||
flow_state);
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
(lvalue, span), flow_state);
|
||||
}
|
||||
Operand::Constant(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn consume_lvalue(&mut self,
|
||||
context: Context,
|
||||
consume_via_drop: ConsumeKind,
|
||||
lvalue_span: (&Lvalue<'tcx>, Span),
|
||||
flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
|
||||
let lvalue = lvalue_span.0;
|
||||
|
||||
let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx);
|
||||
|
||||
// Erase the regions in type before checking whether it moves by
|
||||
// default. There are a few reasons to do this:
|
||||
//
|
||||
// - They should not affect the result.
|
||||
// - It avoids adding new region constraints into the surrounding context,
|
||||
// which would trigger an ICE, since the infcx will have been "frozen" by
|
||||
// the NLL region context.
|
||||
let gcx = self.tcx.global_tcx();
|
||||
let erased_ty = gcx.lift(&self.tcx.erase_regions(&ty)).unwrap();
|
||||
let moves_by_default = erased_ty.moves_by_default(gcx, self.param_env, DUMMY_SP);
|
||||
|
||||
if moves_by_default {
|
||||
let kind = match consume_via_drop {
|
||||
ConsumeKind::Drop => WriteKind::StorageDeadOrDrop,
|
||||
_ => WriteKind::Move,
|
||||
};
|
||||
|
||||
// move of lvalue: check if this is move of already borrowed path
|
||||
self.access_lvalue(context, lvalue_span, (Deep, Write(kind)), flow_state);
|
||||
} else {
|
||||
// copy of lvalue: check if this is "copy of frozen path"
|
||||
// (FIXME: see check_loans.rs)
|
||||
self.access_lvalue(context, lvalue_span, (Deep, Read(ReadKind::Copy)), flow_state);
|
||||
}
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
match consume_via_drop {
|
||||
ConsumeKind::Drop => {
|
||||
// If path is merely being dropped, then we'll already
|
||||
// check the drop flag to see if it is moved (thus we
|
||||
// skip this check in that case).
|
||||
}
|
||||
ConsumeKind::Consume => {
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
lvalue_span, flow_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
@ -1479,22 +1443,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
self.tcx
|
||||
.with_freevars(node_id, |freevars| {
|
||||
for (v, lv) in freevars.iter().zip(lvs) {
|
||||
if let Operand::Consume(Lvalue::Local(l)) = *lv {
|
||||
if local == l {
|
||||
debug!(
|
||||
"find_closure_span: found captured local {:?}",
|
||||
l
|
||||
);
|
||||
return Some(v.span);
|
||||
}
|
||||
self.tcx.with_freevars(node_id, |freevars| {
|
||||
for (v, lv) in freevars.iter().zip(lvs) {
|
||||
match *lv {
|
||||
Operand::Copy(Lvalue::Local(l)) |
|
||||
Operand::Move(Lvalue::Local(l)) if local == l => {
|
||||
debug!(
|
||||
"find_closure_span: found captured local {:?}",
|
||||
l
|
||||
);
|
||||
return Some(v.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
})
|
||||
.map(|var_span| (args_span, var_span))
|
||||
}
|
||||
None
|
||||
}).map(|var_span| (args_span, var_span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -70,14 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
&len, Rvalue::Len(slice.clone()));
|
||||
this.cfg.push_assign(block, source_info, // lt = idx < len
|
||||
<, Rvalue::BinaryOp(BinOp::Lt,
|
||||
Operand::Consume(Lvalue::Local(idx)),
|
||||
Operand::Consume(len.clone())));
|
||||
Operand::Copy(Lvalue::Local(idx)),
|
||||
Operand::Copy(len.clone())));
|
||||
|
||||
let msg = AssertMessage::BoundsCheck {
|
||||
len: Operand::Consume(len),
|
||||
index: Operand::Consume(Lvalue::Local(idx))
|
||||
len: Operand::Move(len),
|
||||
index: Operand::Copy(Lvalue::Local(idx))
|
||||
};
|
||||
let success = this.assert(block, Operand::Consume(lt), true,
|
||||
let success = this.assert(block, Operand::Move(lt), true,
|
||||
msg, expr_span);
|
||||
success.and(slice.index(idx))
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Category::Rvalue(..) => {
|
||||
let operand =
|
||||
unpack!(block = this.as_temp(block, scope, expr));
|
||||
block.and(Operand::Consume(Lvalue::Local(operand)))
|
||||
block.and(Operand::Move(Lvalue::Local(operand)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
|
||||
|
||||
let err = ConstMathErr::Overflow(Op::Neg);
|
||||
block = this.assert(block, Operand::Consume(is_min), false,
|
||||
block = this.assert(block, Operand::Move(is_min), false,
|
||||
AssertMessage::Math(err), expr_span);
|
||||
}
|
||||
block.and(Rvalue::UnaryOp(op, arg))
|
||||
@ -117,7 +117,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
// initialize the box contents:
|
||||
unpack!(block = this.into(&Lvalue::Local(result).deref(), block, value));
|
||||
block.and(Rvalue::Use(Operand::Consume(Lvalue::Local(result))))
|
||||
block.and(Rvalue::Use(Operand::Move(Lvalue::Local(result))))
|
||||
}
|
||||
ExprKind::Cast { source } => {
|
||||
let source = this.hir.mirror(source);
|
||||
@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
.zip(field_types.into_iter())
|
||||
.map(|(n, ty)| match fields_map.get(&n) {
|
||||
Some(v) => v.clone(),
|
||||
None => Operand::Consume(base.clone().field(n, ty))
|
||||
None => this.consume_by_copy_or_move(base.clone().field(n, ty))
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
});
|
||||
|
||||
block = self.assert(block, Operand::Consume(of), false,
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(err), span);
|
||||
|
||||
block.and(Rvalue::Use(Operand::Consume(val)))
|
||||
block.and(Rvalue::Use(Operand::Move(val)))
|
||||
} else {
|
||||
if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
|
||||
// Checking division and remainder is more complex, since we 1. always check
|
||||
@ -348,7 +348,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
self.cfg.push_assign(block, source_info, &is_zero,
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
|
||||
|
||||
block = self.assert(block, Operand::Consume(is_zero), false,
|
||||
block = self.assert(block, Operand::Move(is_zero), false,
|
||||
AssertMessage::Math(zero_err), span);
|
||||
|
||||
// We only need to check for the overflow in one case:
|
||||
@ -368,12 +368,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
self.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, lhs.clone(), min));
|
||||
|
||||
let is_neg_1 = Operand::Consume(is_neg_1);
|
||||
let is_min = Operand::Consume(is_min);
|
||||
let is_neg_1 = Operand::Move(is_neg_1);
|
||||
let is_min = Operand::Move(is_min);
|
||||
self.cfg.push_assign(block, source_info, &of,
|
||||
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
|
||||
|
||||
block = self.assert(block, Operand::Consume(of), false,
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(overflow_err), span);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
match Category::of(&expr.kind).unwrap() {
|
||||
Category::Lvalue => {
|
||||
let lvalue = unpack!(block = this.as_lvalue(block, expr));
|
||||
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
|
||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(lvalue));
|
||||
this.cfg.push_assign(block, source_info, &Lvalue::Local(temp), rvalue);
|
||||
}
|
||||
_ => {
|
||||
|
@ -73,7 +73,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// because AssignOp is only legal for Copy types
|
||||
// (overloaded ops should be desugared into a call).
|
||||
let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty,
|
||||
Operand::Consume(lhs.clone()), rhs));
|
||||
Operand::Copy(lhs.clone()), rhs));
|
||||
this.cfg.push_assign(block, source_info, &lhs, result);
|
||||
|
||||
block.unit()
|
||||
|
@ -773,7 +773,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
self.schedule_drop_for_binding(binding.var_id, binding.span);
|
||||
let rvalue = match binding.binding_mode {
|
||||
BindingMode::ByValue =>
|
||||
Rvalue::Use(Operand::Consume(binding.source)),
|
||||
Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
|
||||
BindingMode::ByRef(region, borrow_kind) =>
|
||||
Rvalue::Ref(region, borrow_kind, binding.source),
|
||||
};
|
||||
|
@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Rvalue::Discriminant(lvalue.clone()));
|
||||
assert_eq!(values.len() + 1, targets.len());
|
||||
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(discr),
|
||||
discr: Operand::Move(discr),
|
||||
switch_ty: discr_ty,
|
||||
values: From::from(values),
|
||||
targets,
|
||||
@ -233,7 +233,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
||||
};
|
||||
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
|
||||
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(lvalue.clone()),
|
||||
true_bb, false_bb))
|
||||
} else {
|
||||
// The switch may be inexhaustive so we
|
||||
@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
v.val.to_const_int().expect("switching on integral")
|
||||
).collect();
|
||||
(targets.clone(), TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(lvalue.clone()),
|
||||
discr: Operand::Copy(lvalue.clone()),
|
||||
switch_ty,
|
||||
values: From::from(values),
|
||||
targets,
|
||||
@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let mut val = Operand::Consume(lvalue.clone());
|
||||
let mut val = Operand::Copy(lvalue.clone());
|
||||
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type &[u8; N].
|
||||
@ -273,7 +273,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let val_slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &val_slice,
|
||||
Rvalue::Cast(CastKind::Unsize, val, ty));
|
||||
val = Operand::Consume(val_slice);
|
||||
val = Operand::Move(val_slice);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &slice,
|
||||
Rvalue::Cast(CastKind::Unsize, array, ty));
|
||||
Operand::Consume(slice)
|
||||
Operand::Move(slice)
|
||||
} else {
|
||||
self.literal_operand(test.span, ty, Literal::Value {
|
||||
value
|
||||
@ -322,7 +322,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(eq_block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(),
|
||||
Operand::Consume(eq_result),
|
||||
Operand::Move(eq_result),
|
||||
block, fail));
|
||||
vec![block, fail]
|
||||
} else {
|
||||
@ -335,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
|
||||
let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
|
||||
let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
|
||||
let val = Operand::Consume(lvalue.clone());
|
||||
let val = Operand::Copy(lvalue.clone());
|
||||
|
||||
let fail = self.cfg.start_new_block();
|
||||
let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
|
||||
@ -362,14 +362,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// result = actual == expected OR result = actual < expected
|
||||
self.cfg.push_assign(block, source_info, &result,
|
||||
Rvalue::BinaryOp(op,
|
||||
Operand::Consume(actual),
|
||||
Operand::Consume(expected)));
|
||||
Operand::Move(actual),
|
||||
Operand::Move(expected)));
|
||||
|
||||
// branch based on result
|
||||
let (false_bb, true_bb) = (self.cfg.start_new_block(),
|
||||
self.cfg.start_new_block());
|
||||
self.cfg.terminate(block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
|
||||
true_bb, false_bb));
|
||||
vec![true_bb, false_bb]
|
||||
}
|
||||
@ -394,7 +394,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// branch based on result
|
||||
let target_block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
|
||||
target_block, fail_block));
|
||||
target_block
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use rustc::ty::{self, Ty};
|
||||
|
||||
use rustc::mir::*;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
/// Add a new temporary value of type `ty` storing the result of
|
||||
@ -133,4 +133,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
});
|
||||
temp
|
||||
}
|
||||
|
||||
pub fn consume_by_copy_or_move(&self, lvalue: Lvalue<'tcx>) -> Operand<'tcx> {
|
||||
let tcx = self.hir.tcx();
|
||||
let ty = lvalue.ty(&self.local_decls, tcx).to_ty(tcx);
|
||||
if self.hir.type_moves_by_default(ty, DUMMY_SP) {
|
||||
Operand::Move(lvalue)
|
||||
} else {
|
||||
Operand::Copy(lvalue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ use rustc::mir::tcx::RvalueInitializationState;
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec};
|
||||
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::mem;
|
||||
|
||||
@ -28,16 +26,12 @@ use super::IllegalMoveOriginKind::*;
|
||||
struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
data: MoveData<'tcx>,
|
||||
errors: Vec<MoveError<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
||||
fn new(mir: &'a Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
-> Self {
|
||||
fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
|
||||
let mut move_paths = IndexVec::new();
|
||||
let mut path_map = IndexVec::new();
|
||||
let mut init_path_map = IndexVec::new();
|
||||
@ -45,7 +39,6 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
||||
MoveDataBuilder {
|
||||
mir,
|
||||
tcx,
|
||||
param_env,
|
||||
errors: Vec::new(),
|
||||
data: MoveData {
|
||||
moves: IndexVec::new(),
|
||||
@ -213,12 +206,10 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<MoveData<'tcx>,
|
||||
(MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
|
||||
let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
|
||||
let mut builder = MoveDataBuilder::new(mir, tcx);
|
||||
|
||||
builder.gather_args();
|
||||
|
||||
@ -289,7 +280,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||
}
|
||||
StatementKind::StorageLive(_) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.gather_move(&Lvalue::Local(local), true);
|
||||
self.gather_move(&Lvalue::Local(local));
|
||||
}
|
||||
StatementKind::SetDiscriminant{ .. } => {
|
||||
span_bug!(stmt.source_info.span,
|
||||
@ -348,7 +339,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||
TerminatorKind::Unreachable => { }
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(&Lvalue::Local(RETURN_POINTER), false);
|
||||
self.gather_move(&Lvalue::Local(RETURN_POINTER));
|
||||
}
|
||||
|
||||
TerminatorKind::Assert { .. } |
|
||||
@ -361,7 +352,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
|
||||
self.gather_move(location, false);
|
||||
self.gather_move(location);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
|
||||
self.create_move_path(location);
|
||||
@ -383,25 +374,17 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
||||
|
||||
fn gather_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Constant(..) => {} // not-a-move
|
||||
Operand::Consume(ref lval) => { // a move
|
||||
self.gather_move(lval, false);
|
||||
Operand::Constant(..) |
|
||||
Operand::Copy(..) => {} // not-a-move
|
||||
Operand::Move(ref lval) => { // a move
|
||||
self.gather_move(lval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_move(&mut self, lval: &Lvalue<'tcx>, force: bool) {
|
||||
fn gather_move(&mut self, lval: &Lvalue<'tcx>) {
|
||||
debug!("gather_move({:?}, {:?})", self.loc, lval);
|
||||
|
||||
let tcx = self.builder.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
let lv_ty = lval.ty(self.builder.mir, tcx).to_ty(tcx);
|
||||
let erased_ty = gcx.lift(&tcx.erase_regions(&lv_ty)).unwrap();
|
||||
if !force && !erased_ty.moves_by_default(gcx, self.builder.param_env, DUMMY_SP) {
|
||||
debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", self.loc, lval, lv_ty);
|
||||
return
|
||||
}
|
||||
|
||||
let path = match self.move_path_for(lval) {
|
||||
Ok(path) | Err(MoveError::UnionMove { path }) => path,
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
|
@ -293,10 +293,8 @@ impl<'tcx> MoveError<'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
|
||||
pub fn gather_moves(mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
|
||||
builder::gather_moves(mir, tcx, param_env)
|
||||
builder::gather_moves(mir, tcx)
|
||||
}
|
||||
}
|
||||
|
@ -252,6 +252,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
pub fn check_overflow(&self) -> bool {
|
||||
self.check_overflow
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.infcx.type_moves_by_default(self.param_env, ty, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
|
||||
|
@ -385,7 +385,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Use(Operand::Consume(rcvr))
|
||||
Rvalue::Use(Operand::Copy(rcvr))
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
@ -448,7 +448,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
// `let loc = Clone::clone(ref_loc);`
|
||||
self.block(vec![statement], TerminatorKind::Call {
|
||||
func,
|
||||
args: vec![Operand::Consume(ref_loc)],
|
||||
args: vec![Operand::Move(ref_loc)],
|
||||
destination: Some((loc.clone(), next)),
|
||||
cleanup: Some(cleanup),
|
||||
}, false);
|
||||
@ -470,14 +470,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
let compute_cond = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
cond.clone(),
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Consume(end), Operand::Consume(beg))
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
)
|
||||
);
|
||||
|
||||
// `if end != beg { goto loop_body; } else { goto loop_end; }`
|
||||
self.block(
|
||||
vec![compute_cond],
|
||||
TerminatorKind::if_(tcx, Operand::Consume(cond), loop_body, loop_end),
|
||||
TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
|
||||
is_cleanup
|
||||
);
|
||||
}
|
||||
@ -547,7 +547,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
ret_field,
|
||||
Rvalue::Use(Operand::Consume(cloned))
|
||||
Rvalue::Use(Operand::Move(cloned))
|
||||
)
|
||||
),
|
||||
self.make_statement(
|
||||
@ -555,7 +555,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
Lvalue::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Consume(Lvalue::Local(beg)),
|
||||
Operand::Copy(Lvalue::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
@ -568,7 +568,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Use(Operand::Consume(ret.clone())),
|
||||
Rvalue::Use(Operand::Move(ret.clone())),
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
@ -611,7 +611,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
Lvalue::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Consume(Lvalue::Local(beg)),
|
||||
Operand::Copy(Lvalue::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
@ -666,7 +666,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Aggregate(
|
||||
box kind,
|
||||
returns.into_iter().map(Operand::Consume).collect()
|
||||
returns.into_iter().map(Operand::Move).collect()
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -705,8 +705,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let mut statements = vec![];
|
||||
|
||||
let rcvr = match rcvr_adjustment {
|
||||
Adjustment::Identity => Operand::Consume(rcvr_l),
|
||||
Adjustment::Deref => Operand::Consume(rcvr_l.deref()),
|
||||
Adjustment::Identity => Operand::Move(rcvr_l),
|
||||
Adjustment::Deref => Operand::Copy(rcvr_l.deref()),
|
||||
Adjustment::RefMut => {
|
||||
// let rcvr = &mut rcvr;
|
||||
let ref_rcvr = local_decls.push(temp_decl(
|
||||
@ -724,7 +724,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
|
||||
)
|
||||
});
|
||||
Operand::Consume(Lvalue::Local(ref_rcvr))
|
||||
Operand::Move(Lvalue::Local(ref_rcvr))
|
||||
}
|
||||
};
|
||||
|
||||
@ -750,11 +750,11 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
if let Some(untuple_args) = untuple_args {
|
||||
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
|
||||
let arg_lv = Lvalue::Local(Local::new(1+1));
|
||||
Operand::Consume(arg_lv.field(Field::new(i), *ity))
|
||||
Operand::Move(arg_lv.field(Field::new(i), *ity))
|
||||
}));
|
||||
} else {
|
||||
args.extend((1..sig.inputs().len()).map(|i| {
|
||||
Operand::Consume(Lvalue::Local(Local::new(1+i)))
|
||||
Operand::Move(Lvalue::Local(Local::new(1+i)))
|
||||
}));
|
||||
}
|
||||
|
||||
@ -868,7 +868,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
||||
Rvalue::Aggregate(
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None),
|
||||
(1..sig.inputs().len()+1).map(|i| {
|
||||
Operand::Consume(Lvalue::Local(Local::new(i)))
|
||||
Operand::Move(Lvalue::Local(Local::new(i)))
|
||||
}).collect()
|
||||
)
|
||||
)
|
||||
|
@ -132,7 +132,7 @@ fn add_move_for_packed_drop<'a, 'tcx>(
|
||||
patch.add_statement(
|
||||
loc, StatementKind::StorageLive(temp));
|
||||
patch.add_assign(loc, Lvalue::Local(temp),
|
||||
Rvalue::Use(Operand::Consume(location.clone())));
|
||||
Rvalue::Use(Operand::Move(location.clone())));
|
||||
patch.patch_terminator(loc.block, TerminatorKind::Drop {
|
||||
location: Lvalue::Local(temp),
|
||||
target: storage_dead_block,
|
||||
|
@ -260,7 +260,8 @@ impl MirPass for AddValidation {
|
||||
.chain(
|
||||
args.iter().filter_map(|op| {
|
||||
match op {
|
||||
&Operand::Consume(ref lval) =>
|
||||
&Operand::Copy(ref lval) |
|
||||
&Operand::Move(ref lval) =>
|
||||
Some(lval_to_operand(lval.clone())),
|
||||
&Operand::Constant(..) => { None },
|
||||
}
|
||||
@ -353,14 +354,17 @@ impl MirPass for AddValidation {
|
||||
block_data.statements.insert(i, release_stmt);
|
||||
}
|
||||
// Casts can change what validation does (e.g. unsizing)
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Consume(_), _))
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Copy(_), _)) |
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Move(_), _))
|
||||
if kind != CastKind::Misc =>
|
||||
{
|
||||
// Due to a lack of NLL; we can't capture anything directly here.
|
||||
// Instead, we have to re-match and clone there.
|
||||
let (dest_lval, src_lval) = match block_data.statements[i].kind {
|
||||
StatementKind::Assign(ref dest_lval,
|
||||
Rvalue::Cast(_, Operand::Consume(ref src_lval), _)) =>
|
||||
Rvalue::Cast(_, Operand::Copy(ref src_lval), _)) |
|
||||
StatementKind::Assign(ref dest_lval,
|
||||
Rvalue::Cast(_, Operand::Move(ref src_lval), _)) =>
|
||||
{
|
||||
(dest_lval.clone(), src_lval.clone())
|
||||
},
|
||||
|
@ -126,7 +126,8 @@ impl MirPass for CopyPropagation {
|
||||
StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
|
||||
local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Consume(ref src_lvalue) => {
|
||||
Operand::Copy(ref src_lvalue) |
|
||||
Operand::Move(ref src_lvalue) => {
|
||||
Action::local_copy(&mir, &def_use_analysis, src_lvalue)
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
@ -173,7 +174,11 @@ fn eliminate_self_assignments<'tcx>(
|
||||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(local),
|
||||
Rvalue::Use(Operand::Consume(Lvalue::Local(src_local))),
|
||||
Rvalue::Use(Operand::Copy(Lvalue::Local(src_local))),
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(local),
|
||||
Rvalue::Use(Operand::Move(Lvalue::Local(src_local))),
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
_ => {
|
||||
continue;
|
||||
@ -351,7 +356,8 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
||||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
|
||||
Operand::Copy(Lvalue::Local(local)) |
|
||||
Operand::Move(Lvalue::Local(local)) if local == self.dest_local => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ impl MirPass for ElaborateDrops {
|
||||
_ => return
|
||||
}
|
||||
let param_env = tcx.param_env(src.def_id);
|
||||
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
|
||||
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
|
||||
let elaborate_patch = {
|
||||
let mir = &*mir;
|
||||
let env = MoveDataParamEnv {
|
||||
@ -278,7 +278,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> {
|
||||
self.ctxt.drop_flag(path).map(Operand::Consume)
|
||||
self.ctxt.drop_flag(path).map(Operand::Copy)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
||||
let ret_val = match data.terminator().kind {
|
||||
TerminatorKind::Return => Some((1,
|
||||
None,
|
||||
Operand::Consume(Lvalue::Local(self.new_ret_local)),
|
||||
Operand::Move(Lvalue::Local(self.new_ret_local)),
|
||||
None)),
|
||||
TerminatorKind::Yield { ref value, resume, drop } => Some((0,
|
||||
Some(resume),
|
||||
@ -452,7 +452,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let default_block = insert_term_block(mir, default);
|
||||
|
||||
let switch = TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
|
||||
discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)),
|
||||
switch_ty: tcx.types.u32,
|
||||
values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
|
||||
targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(),
|
||||
|
@ -456,7 +456,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
// needs to generate the cast.
|
||||
// FIXME: we should probably just generate correct MIR in the first place...
|
||||
|
||||
let arg = if let Operand::Consume(ref lval) = args[0] {
|
||||
let arg = if let Operand::Move(ref lval) = args[0] {
|
||||
lval.clone()
|
||||
} else {
|
||||
bug!("Constant arg to \"box_free\"");
|
||||
@ -535,7 +535,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
};
|
||||
let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty);
|
||||
|
||||
let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Consume(ref_tmp), ptr_ty);
|
||||
let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty);
|
||||
|
||||
let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span);
|
||||
let cast_tmp = caller_mir.local_decls.push(cast_tmp);
|
||||
@ -602,7 +602,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
let tuple_tmp_args =
|
||||
tuple_tys.iter().enumerate().map(|(i, ty)| {
|
||||
// This is e.g. `tuple_tmp.0` in our example above.
|
||||
let tuple_field = Operand::Consume(tuple.clone().field(Field::new(i), ty));
|
||||
let tuple_field = Operand::Move(tuple.clone().field(Field::new(i), ty));
|
||||
|
||||
// Spill to a local to make e.g. `tmp0`.
|
||||
self.create_temp_if_necessary(tuple_field, callsite, caller_mir)
|
||||
@ -627,7 +627,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
// FIXME: Analysis of the usage of the arguments to avoid
|
||||
// unnecessary temporaries.
|
||||
|
||||
if let Operand::Consume(Lvalue::Local(local)) = arg {
|
||||
if let Operand::Move(Lvalue::Local(local)) = arg {
|
||||
if caller_mir.local_kind(local) == LocalKind::Temp {
|
||||
// Reuse the operand if it's a temporary already
|
||||
return local;
|
||||
|
@ -59,7 +59,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
||||
}
|
||||
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
||||
};
|
||||
*rvalue = Rvalue::Use(Operand::Consume(new_lvalue))
|
||||
*rvalue = Rvalue::Use(Operand::Copy(new_lvalue))
|
||||
}
|
||||
|
||||
if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
|
||||
|
@ -105,7 +105,7 @@ impl Lower128Bit {
|
||||
rhs,
|
||||
rhs_override_ty.unwrap())),
|
||||
});
|
||||
rhs = Operand::Consume(Lvalue::Local(local));
|
||||
rhs = Operand::Move(Lvalue::Local(local));
|
||||
}
|
||||
|
||||
let call_did = check_lang_item_type(
|
||||
@ -237,4 +237,4 @@ fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsK
|
||||
_ => bug!("That should be all the checked ones?"),
|
||||
};
|
||||
Some(i)
|
||||
}
|
||||
}
|
||||
|
@ -519,7 +519,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
|
||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||
match *operand {
|
||||
Operand::Consume(ref lvalue) => {
|
||||
Operand::Copy(ref lvalue) |
|
||||
Operand::Move(ref lvalue) => {
|
||||
self.nest(|this| {
|
||||
this.super_operand(operand, location);
|
||||
this.try_consume();
|
||||
@ -872,10 +873,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
self.const_fn_arg_vars.insert(index.index()) {
|
||||
|
||||
// Direct use of an argument is permitted.
|
||||
if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
|
||||
if self.mir.local_kind(local) == LocalKind::Arg {
|
||||
return;
|
||||
match *rvalue {
|
||||
Rvalue::Use(Operand::Copy(Lvalue::Local(local))) |
|
||||
Rvalue::Use(Operand::Move(Lvalue::Local(local))) => {
|
||||
if self.mir.local_kind(local) == LocalKind::Arg {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
|
@ -45,7 +45,7 @@ impl MirPass for SanityCheck {
|
||||
|
||||
let attributes = tcx.get_attrs(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
|
||||
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
|
||||
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
|
||||
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
|
||||
let flow_inits =
|
||||
@ -124,7 +124,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
};
|
||||
assert!(args.len() == 1);
|
||||
let peek_arg_lval = match args[0] {
|
||||
mir::Operand::Consume(ref lval @ mir::Lvalue::Local(_)) => Some(lval),
|
||||
mir::Operand::Copy(ref lval @ mir::Lvalue::Local(_)) |
|
||||
mir::Operand::Move(ref lval @ mir::Lvalue::Local(_)) => Some(lval),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
@ -498,7 +498,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(discr),
|
||||
discr: Operand::Move(discr),
|
||||
switch_ty: discr_ty,
|
||||
values: From::from(values.to_owned()),
|
||||
targets: blocks,
|
||||
@ -536,7 +536,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
kind: TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, drop_fn.def_id, substs,
|
||||
self.source_info.span),
|
||||
args: vec![Operand::Consume(Lvalue::Local(ref_lvalue))],
|
||||
args: vec![Operand::Move(Lvalue::Local(ref_lvalue))],
|
||||
destination: Some((unit_temp, succ)),
|
||||
cleanup: unwind.into_option(),
|
||||
},
|
||||
@ -572,7 +572,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
ptr_based: bool)
|
||||
-> BasicBlock
|
||||
{
|
||||
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
|
||||
let copy = |lv: &Lvalue<'tcx>| Operand::Copy(lv.clone());
|
||||
let move_ = |lv: &Lvalue<'tcx>| Operand::Move(lv.clone());
|
||||
let tcx = self.tcx();
|
||||
|
||||
let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
|
||||
@ -584,14 +585,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
|
||||
let one = self.constant_usize(1);
|
||||
let (ptr_next, cur_next) = if ptr_based {
|
||||
(Rvalue::Use(use_(&Lvalue::Local(cur))),
|
||||
Rvalue::BinaryOp(BinOp::Offset, use_(&Lvalue::Local(cur)), one))
|
||||
(Rvalue::Use(copy(&Lvalue::Local(cur))),
|
||||
Rvalue::BinaryOp(BinOp::Offset, copy(&Lvalue::Local(cur)), one))
|
||||
} else {
|
||||
(Rvalue::Ref(
|
||||
tcx.types.re_erased,
|
||||
BorrowKind::Mut,
|
||||
self.lvalue.clone().index(cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, use_(&Lvalue::Local(cur)), one))
|
||||
Rvalue::BinaryOp(BinOp::Add, copy(&Lvalue::Local(cur)), one))
|
||||
};
|
||||
|
||||
let drop_block = BasicBlockData {
|
||||
@ -611,13 +612,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
let loop_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
|
||||
use_(&Lvalue::Local(cur)),
|
||||
use_(length_or_end)))
|
||||
copy(&Lvalue::Local(cur)),
|
||||
copy(length_or_end)))
|
||||
],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::if_(tcx, use_(can_go), succ, drop_block)
|
||||
kind: TerminatorKind::if_(tcx, move_(can_go), succ, drop_block)
|
||||
})
|
||||
};
|
||||
let loop_block = self.elaborator.patch().new_block(loop_block);
|
||||
@ -642,14 +643,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
|
||||
let tcx = self.tcx();
|
||||
|
||||
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
|
||||
let move_ = |lv: &Lvalue<'tcx>| Operand::Move(lv.clone());
|
||||
let size = &Lvalue::Local(self.new_temp(tcx.types.usize));
|
||||
let size_is_zero = &Lvalue::Local(self.new_temp(tcx.types.bool));
|
||||
let base_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
|
||||
self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq,
|
||||
use_(size),
|
||||
move_(size),
|
||||
self.constant_usize(0)))
|
||||
],
|
||||
is_cleanup: self.unwind.is_cleanup(),
|
||||
@ -657,7 +658,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::if_(
|
||||
tcx,
|
||||
use_(size_is_zero),
|
||||
move_(size_is_zero),
|
||||
self.drop_loop_pair(ety, false),
|
||||
self.drop_loop_pair(ety, true)
|
||||
)
|
||||
@ -718,11 +719,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone()
|
||||
)));
|
||||
drop_block_stmts.push(self.assign(&cur, Rvalue::Cast(
|
||||
CastKind::Misc, Operand::Consume(tmp.clone()), iter_ty
|
||||
CastKind::Misc, Operand::Move(tmp.clone()), iter_ty
|
||||
)));
|
||||
drop_block_stmts.push(self.assign(&length_or_end,
|
||||
Rvalue::BinaryOp(BinOp::Offset,
|
||||
Operand::Consume(cur.clone()), Operand::Consume(length.clone())
|
||||
Operand::Copy(cur.clone()), Operand::Move(length.clone())
|
||||
)));
|
||||
} else {
|
||||
// index = 0 (length already pushed)
|
||||
@ -854,7 +855,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
|
||||
let call = TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
|
||||
args: vec![Operand::Consume(self.lvalue.clone())],
|
||||
args: vec![Operand::Move(self.lvalue.clone())],
|
||||
destination: Some((unit_temp, target)),
|
||||
cleanup: None
|
||||
}; // FIXME(#6393)
|
||||
|
@ -273,7 +273,8 @@ impl<'tcx> Visitor<'tcx> for DefsUsesVisitor {
|
||||
LvalueContext::Borrow { .. } |
|
||||
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Consume |
|
||||
LvalueContext::Copy |
|
||||
LvalueContext::Move |
|
||||
LvalueContext::Validate => {
|
||||
if self.mode.include_regular_use {
|
||||
self.defs_uses.add_use(local);
|
||||
|
@ -181,7 +181,8 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
location: Location) {
|
||||
self.record("Operand", operand);
|
||||
self.record(match *operand {
|
||||
Operand::Consume(..) => "Operand::Consume",
|
||||
Operand::Copy(..) => "Operand::Copy",
|
||||
Operand::Move(..) => "Operand::Move",
|
||||
Operand::Constant(..) => "Operand::Constant",
|
||||
}, operand);
|
||||
self.super_operand(operand, location);
|
||||
|
@ -121,7 +121,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
// box_free(x) shares with `drop x` the property that it
|
||||
// is not guaranteed to be statically dominated by the
|
||||
// definition of x, so x must always be in an alloca.
|
||||
if let mir::Operand::Consume(ref lvalue) = args[0] {
|
||||
if let mir::Operand::Move(ref lvalue) = args[0] {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Drop, location);
|
||||
}
|
||||
}
|
||||
@ -140,7 +140,11 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
|
||||
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||
if let LvalueContext::Consume = context {
|
||||
let is_consume = match context {
|
||||
LvalueContext::Copy | LvalueContext::Move => true,
|
||||
_ => false
|
||||
};
|
||||
if is_consume {
|
||||
let base_ty = proj.base.ty(self.cx.mir, ccx.tcx());
|
||||
let base_ty = self.cx.monomorphize(&base_ty);
|
||||
|
||||
@ -154,10 +158,10 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
||||
let layout = ccx.layout_of(base_ty.to_ty(ccx.tcx()));
|
||||
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
|
||||
// Recurse as a `Consume` instead of `Projection`,
|
||||
// Recurse with the same context, instead of `Projection`,
|
||||
// potentially stopping at non-operand projections,
|
||||
// which would trigger `mark_as_lvalue` on locals.
|
||||
self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||
self.visit_lvalue(&proj.base, context, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -165,7 +169,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
|
||||
// A deref projection only reads the pointer, never needs the lvalue.
|
||||
if let mir::ProjectionElem::Deref = proj.elem {
|
||||
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||
return self.visit_lvalue(&proj.base, LvalueContext::Copy, location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +188,8 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
LvalueContext::StorageLive |
|
||||
LvalueContext::StorageDead |
|
||||
LvalueContext::Validate |
|
||||
LvalueContext::Consume => {}
|
||||
LvalueContext::Copy |
|
||||
LvalueContext::Move => {}
|
||||
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Store |
|
||||
|
@ -517,7 +517,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
|
||||
match *arg {
|
||||
mir::Operand::Consume(_) => {
|
||||
mir::Operand::Copy(_) |
|
||||
mir::Operand::Move(_) => {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
@ -573,10 +574,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
|
||||
// The callee needs to own the argument memory if we pass it
|
||||
// by-ref, so make a local copy of non-immediate constants.
|
||||
if let (&mir::Operand::Constant(_), Ref(..)) = (arg, op.val) {
|
||||
let tmp = LvalueRef::alloca(&bcx, op.layout, "const");
|
||||
op.val.store(&bcx, tmp);
|
||||
op.val = Ref(tmp.llval, tmp.alignment);
|
||||
match (arg, op.val) {
|
||||
(&mir::Operand::Copy(_), Ref(..)) |
|
||||
(&mir::Operand::Constant(_), Ref(..)) => {
|
||||
let tmp = LvalueRef::alloca(&bcx, op.layout, "const");
|
||||
op.val.store(&bcx, tmp);
|
||||
op.val = Ref(tmp.llval, tmp.alignment);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.trans_argument(&bcx, op, &mut llargs, &fn_ty.args[i]);
|
||||
|
@ -505,7 +505,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
(Base::Value(llprojected), llextra)
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||
let index = &mir::Operand::Copy(mir::Lvalue::Local(index));
|
||||
let llindex = self.const_operand(index, span)?.llval;
|
||||
|
||||
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
||||
@ -540,7 +540,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
debug!("const_operand({:?} @ {:?})", operand, span);
|
||||
let result = match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) |
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
Ok(self.const_lvalue(lvalue, span)?.to_const(span))
|
||||
}
|
||||
|
||||
|
@ -487,7 +487,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
tr_base.project_field(bcx, field.index())
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||
let index = &mir::Operand::Copy(mir::Lvalue::Local(index));
|
||||
let index = self.trans_operand(bcx, index);
|
||||
let llindex = index.immediate();
|
||||
tr_base.project_index(bcx, llindex)
|
||||
|
@ -308,7 +308,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
debug!("trans_operand(operand={:?})", operand);
|
||||
|
||||
match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) |
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
self.trans_consume(bcx, lvalue)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user