]> git.lizzy.rs Git - rust.git/commitdiff
MIR: split Operand::Consume into Copy and Move.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Fri, 17 Nov 2017 15:19:57 +0000 (17:19 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Tue, 28 Nov 2017 02:18:32 +0000 (04:18 +0200)
35 files changed:
src/librustc/ich/impls_mir.rs
src/librustc/mir/mod.rs
src/librustc/mir/tcx.rs
src/librustc/mir/visit.rs
src/librustc_mir/borrow_check.rs
src/librustc_mir/build/expr/as_lvalue.rs
src/librustc_mir/build/expr/as_operand.rs
src/librustc_mir/build/expr/as_rvalue.rs
src/librustc_mir/build/expr/as_temp.rs
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/matches/mod.rs
src/librustc_mir/build/matches/test.rs
src/librustc_mir/build/misc.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/dataflow/move_paths/mod.rs
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/add_moves_for_packed_drops.rs
src/librustc_mir/transform/add_validation.rs
src/librustc_mir/transform/copy_prop.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/transform/generator.rs
src/librustc_mir/transform/inline.rs
src/librustc_mir/transform/instcombine.rs
src/librustc_mir/transform/lower_128bit.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/rustc_peek.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_mir/util/liveness.rs
src/librustc_passes/mir_stats.rs
src/librustc_trans/mir/analyze.rs
src/librustc_trans/mir/block.rs
src/librustc_trans/mir/constant.rs
src/librustc_trans/mir/lvalue.rs
src/librustc_trans/mir/operand.rs

index d9244c32dc429b6ca847b23d01330e69e0b0d867..e40d07d936bbcba40bd84b5a98b6e5927baae3c0 100644 (file)
@@ -420,7 +420,10 @@ fn hash_stable<W: StableHasherResult>(&self,
         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) => {
index 266f60094c30952ef0666a90a0e57f85216a7486..d5df90a5ea02c5849c37ccaf098e679906b9092e 100644 (file)
@@ -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 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
         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 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
 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)
         }
     }
index d645a00e15781a3436c9bdbeb696d4e184c9ab42..073f4cafc9dc6883bd5969237e0c1b0303e2d37a 100644 (file)
@@ -230,7 +230,8 @@ pub fn ty<'a, 'gcx, D>(&self, local_decls: &D, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> T
         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,
         }
     }
index 5f2f5b79cc698580338401d5664d12e2367296ad..b9db7d236c0d21c8e0d510002839dbd67362d261 100644 (file)
@@ -611,8 +611,11 @@ fn super_operand(&mut self,
                              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 @@ fn super_projection_elem(&mut self,
                         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 @@ pub fn is_mutating_use(&self) -> bool {
             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 @@ pub fn is_nonmutating_use(&self) -> bool {
         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 |
index ef41621c4114346e8e05d4183e0b360584f15f0e..19d121843cbfae2145a54f849ed9cf1beb1e2cc8 100644 (file)
@@ -25,7 +25,7 @@
 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 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 @@ fn visit_statement_entry(&mut self,
                                    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 @@ fn visit_statement_entry(&mut self,
                     }
                 }
                 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 @@ fn visit_terminator_entry(&mut self,
         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 @@ fn visit_terminator_entry(&mut self,
                                    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 @@ fn visit_terminator_entry(&mut self,
             }
             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 @@ fn visit_terminator_entry(&mut self,
 
             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 @@ fn visit_terminator_entry(&mut self,
 #[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 @@ fn consume_rvalue(&mut self,
             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 @@ fn consume_rvalue(&mut self,
 
             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 @@ fn consume_rvalue(&mut self,
 
             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,62 +681,33 @@ fn consume_rvalue(&mut self,
 
     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::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);
-        }
+            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.
-        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).
+                // Finally, check if path was already moved.
+                self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
+                                            (lvalue, span), flow_state);
             }
-            ConsumeKind::Consume => {
+            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);
+                                            (lvalue, span), flow_state);
             }
+            Operand::Constant(_) => {}
         }
     }
 }
@@ -1479,22 +1443,22 @@ fn find_closure_span(
                             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
                     };
index 69d0dd992281ed86e3aec2ba18db9ef71c1a5de1..46c15ede4d923b1df09afeb54506dac90819537b 100644 (file)
@@ -70,14 +70,14 @@ fn expr_as_lvalue(&mut self,
                                      &len, Rvalue::Len(slice.clone()));
                 this.cfg.push_assign(block, source_info, // lt = idx < len
                                      &lt, 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))
             }
index ea6e4342098bc6061ab78cd52c219b5af14ef3f7..b9d03cb2d4544c290a760ed293fb68c78a30396c 100644 (file)
@@ -74,7 +74,7 @@ fn expr_as_operand(&mut self,
             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)))
             }
         }
     }
index d17f00b489c318bb4a6bd3c99510983e374d0217..b6f2477a930122a0ab7ac334f53804cdb2b77a21 100644 (file)
@@ -90,7 +90,7 @@ fn expr_as_rvalue(&mut self,
                                          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 @@ fn expr_as_rvalue(&mut self,
 
                 // 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 @@ fn expr_as_rvalue(&mut self,
                         .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 @@ pub fn build_binary_op(&mut self, mut block: BasicBlock,
                 }
             });
 
-            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 @@ pub fn build_binary_op(&mut self, mut block: BasicBlock,
                 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 @@ pub fn build_binary_op(&mut self, mut block: BasicBlock,
                     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);
                 }
             }
index ba422a8183160fd3d5eacd3e8526c5354232d24b..a292d8e54980b4c18d9e6e1d851f06ac5b7f8f98 100644 (file)
@@ -67,7 +67,7 @@ fn expr_as_temp(&mut self,
         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);
             }
             _ => {
index 3cfb0ff4010da753d3ad7fc32828eb258437ef2a..1878258f90846ff52a81728ae0bdd4cf4ee3c230 100644 (file)
@@ -73,7 +73,7 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
                 // 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()
index b65d859e7d7568ab596eda5dc5ee54d2dc079034..fb6458aa115da7df150404373f15f6735f5e3d68 100644 (file)
@@ -773,7 +773,7 @@ fn bind_matched_candidate(&mut self,
             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),
             };
index 02a7bc83f6ee822cece374180c16a62a9ea554c9..b3a46508cf0b232bc641c20806085c4f534ab651 100644 (file)
@@ -215,7 +215,7 @@ pub fn perform_test(&mut self,
                                      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 @@ pub fn perform_test(&mut self,
                         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 @@ pub fn perform_test(&mut self,
                         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 @@ pub fn perform_test(&mut self,
             }
 
             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 @@ pub fn perform_test(&mut self,
                             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 @@ pub fn perform_test(&mut self,
                     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 @@ pub fn perform_test(&mut self,
                     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 @@ pub fn perform_test(&mut self,
                 // 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 @@ pub fn perform_test(&mut self,
                 // 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 @@ fn compare(&mut self,
         // 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
     }
index 1976b70ac0a2367c98f5c556a065518fe75418bb..1b689aa2132b4ec9f5a4c17b0b600d43b324bfb6 100644 (file)
@@ -19,7 +19,7 @@
 
 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 @@ pub fn push_usize(&mut self,
             });
         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)
+        }
+    }
 }
index af582b8cf66a18bcade67e4b28cd4aab537df73b..b8a9103c8167caf975f80f62cac741c75c9f8ce1 100644 (file)
@@ -14,8 +14,6 @@
 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;
 
 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 @@ fn new(mir: &'a Mir<'tcx>,
         MoveDataBuilder {
             mir,
             tcx,
-            param_env,
             errors: Vec::new(),
             data: MoveData {
                 moves: IndexVec::new(),
@@ -213,12 +206,10 @@ fn finalize(self) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<MoveError<'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 @@ fn gather_statement(&mut self, stmt: &Statement<'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 @@ fn gather_terminator(&mut self, term: &Terminator<'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 @@ fn gather_terminator(&mut self, term: &Terminator<'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 @@ fn gather_terminator(&mut self, term: &Terminator<'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 { .. }) => {
index 4703dd8a2afa6aa12106a5bd76769433421c45f5..69877367c7688755ad6961c67e82ca27daebcfb0 100644 (file)
@@ -293,10 +293,8 @@ fn cannot_move_out_of(span: Span, kind: IllegalMoveOriginKind<'tcx>) -> Self {
 }
 
 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)
     }
 }
index b1f4b849b8928f4ec09c1cb9bd4c49f905733532..306b41714a553a1b5ae8eb04d26c22c6435f418b 100644 (file)
@@ -252,6 +252,10 @@ pub fn tables(&self) -> &'a ty::TypeckTables<'gcx> {
     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 {
index 0fa47d809994736a2f839fc0fe74a47c9369168a..119cd35910fd590272c312a8d666b9c703b6e7e9 100644 (file)
@@ -385,7 +385,7 @@ fn copy_shim(&mut self) {
         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 @@ fn make_clone_call(
         // `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 @@ fn loop_header(
         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 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
             self.make_statement(
                 StatementKind::Assign(
                     ret_field,
-                    Rvalue::Use(Operand::Consume(cloned))
+                    Rvalue::Use(Operand::Move(cloned))
                 )
             ),
             self.make_statement(
@@ -555,7 +555,7 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
                     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 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
         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 @@ fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
                 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 @@ fn tuple_like_shim(&mut self, tys: &[ty::Ty<'tcx>], kind: AggregateKind<'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()
                 )
             )
index 297bc76d472f50a87060f0c104173339986fb2f6..2cb8cb60e07d716ed5bbc17026f1da3bd7396535 100644 (file)
@@ -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,
index c6f2154eaa471e34f29114934b91a816a008b8ce..6021955004e6407cf72b50bed822c94af1c95de4 100644 (file)
@@ -260,7 +260,8 @@ fn run_pass<'a, 'tcx>(&self,
                                 .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 @@ fn run_pass<'a, 'tcx>(&self,
                         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())
                             },
index 2966290c2964c145ec98da79b5c3359b14cf6e00..30048639589ffaa11c6814e6827de838a5e84066 100644 (file)
@@ -126,7 +126,8 @@ fn run_pass<'a, 'tcx>(&self,
                         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 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
         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,
         }
 
index c24256cc92cde133ec0005b12040b0799f68a456..6f94bd1f88f14fb2dbad9c72b2b4ad8b1bcd1949 100644 (file)
@@ -50,7 +50,7 @@ fn run_pass<'a, 'tcx>(&self,
             _ => 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 @@ fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Pat
     }
 
     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)
     }
 }
 
index 43635bcb631b9efbdd39f802d5535babea53e101..fe7ff326f497cc7a0cc1ea6d4f2eaae247b78c88 100644 (file)
@@ -230,7 +230,7 @@ fn visit_basic_block_data(&mut self,
         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(),
index bd3662ca7ce344e5f5848fb014a6ebca787f0b82..844459930b8d76198371264cdcb3b71112a4413a 100644 (file)
@@ -456,7 +456,7 @@ fn dest_needs_borrow(lval: &Lvalue) -> bool {
                     // 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 @@ fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'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 @@ fn make_call_args(
             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 @@ fn create_temp_if_necessary(
         // 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;
index d66d4b14d693d993ed21b7859c4cc89a64a886ad..b45db18eff5f08f3d09ac67ba5195512a0c47c94 100644 (file)
@@ -59,7 +59,7 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
                 }
                 _ => 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) {
index 9dc5fdadbb195cf9739e2332fe452d8a2720f3e9..26621afaba41f29d14b78efcff42fa884c9a91c6 100644 (file)
@@ -105,7 +105,7 @@ fn lower_128bit_ops<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<
                                 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)
-}
\ No newline at end of file
+}
index 97e80de96c5cc0d6ef119eb7c69f2d6bc90cb671..555f0a327980e101e2af07af4075a943a5bdf87d 100644 (file)
@@ -519,7 +519,8 @@ fn visit_lvalue(&mut self,
 
     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 @@ fn visit_assign(&mut self,
                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.
index 32d4a14c7f75730d7dc124959da4b3c42163e173..cc8a6e66da1824fe1ecd403de75e2b2df3c1d00e 100644 (file)
@@ -45,7 +45,7 @@ fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         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,
     };
 
index 1852712a083751a02410e93fb3a3cbfe9a027590..bb8dbd64c367ef9e121623ed18430c8102c6afc0 100644 (file)
@@ -498,7 +498,7 @@ fn adt_switch_block(&mut self,
             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 @@ fn destructor_call_block<'a>(&mut self, (succ, unwind): (BasicBlock, Unwind))
                 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 @@ fn drop_loop(&mut self,
                  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 @@ fn drop_loop(&mut self,
 
         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 @@ fn drop_loop(&mut self,
         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 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
 
         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 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
                 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 @@ fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock {
                 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 @@ fn unelaborated_free_block<'a>(
 
         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)
index 4b165a71c81b37639ac72d1e6e7f8c742da826dc..9afd5a1483fbffe9055a92ec4b450c443d3bcb5e 100644 (file)
@@ -273,7 +273,8 @@ fn visit_local(&mut self, &local: &Local, context: LvalueContext<'tcx>, _: Locat
             LvalueContext::Borrow { .. } |
 
             LvalueContext::Inspect |
-            LvalueContext::Consume |
+            LvalueContext::Copy |
+            LvalueContext::Move |
             LvalueContext::Validate => {
                 if self.mode.include_regular_use {
                     self.defs_uses.add_use(local);
index ab41ad1e0995056c46635618869377fffad65af6..6054d6c24101ac6216f0967ba35787d9c11ce095 100644 (file)
@@ -181,7 +181,8 @@ fn visit_operand(&mut self,
                      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);
index 223379527c989aee07d5a0409d7a6ea034201228..77f607e55143541b938bdc5634a9b666e15feca8 100644 (file)
@@ -121,7 +121,7 @@ fn visit_terminator_kind(&mut self,
                 // 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 @@ fn visit_lvalue(&mut self,
 
         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 @@ fn visit_lvalue(&mut self,
                 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 @@ fn visit_lvalue(&mut self,
 
             // 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 @@ fn visit_local(&mut self,
             LvalueContext::StorageLive |
             LvalueContext::StorageDead |
             LvalueContext::Validate |
-            LvalueContext::Consume => {}
+            LvalueContext::Copy |
+            LvalueContext::Move => {}
 
             LvalueContext::Inspect |
             LvalueContext::Store |
index f43eba36a8232fa8fdb188efb13e73ec93bc8320..61811a62c6630b58e6436493ac3fabb83b6eef9a 100644 (file)
@@ -517,7 +517,8 @@ fn trans_terminator(&mut self,
                         // 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 @@ fn trans_terminator(&mut self,
 
                     // 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]);
index 8c013330e5bcb506dd792ee1103612da777f2adc..e38af774a51ff782105bc74c63a430ababfae4a6 100644 (file)
@@ -505,7 +505,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
                         (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 @@ fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
                      -> 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))
             }
 
index 891d52045c217a2ae99a7de9a17ff90d7dc8378e..b7470e470bc14242475c8deac7f647f2b394ab19 100644 (file)
@@ -487,7 +487,7 @@ pub fn trans_lvalue(&mut self,
                         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)
index 8c43bded1bf217415ab4ca75e25eb5a6623e0e7e..21770c1d792574717c8582f697f375ea664d51c0 100644 (file)
@@ -308,7 +308,8 @@ pub fn trans_operand(&mut self,
         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)
             }