From 0477319afb369d0e2bdb29b813ef10660a6594f5 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 21 Nov 2017 01:50:04 +0200 Subject: [PATCH 1/6] rustc_mir: move storage_dead_or_drop_error_reported logic to access_lvalue. --- src/librustc_mir/borrow_check.rs | 82 ++++++++++++++------------------ 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index 9a05bbea48704..ef41621c41143 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -140,7 +140,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, node_id: id, move_data: &mdpe.move_data, param_env: param_env, - storage_drop_or_dead_error_reported: FxHashSet(), + storage_dead_or_drop_error_reported: FxHashSet(), }; let mut state = InProgress::new(flow_borrows, @@ -159,10 +159,10 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { node_id: ast::NodeId, move_data: &'cx MoveData<'tcx>, param_env: ParamEnv<'gcx>, - /// This field keeps track of when storage drop or dead errors are reported + /// This field keeps track of when storage dead or drop errors are reported /// in order to stop duplicate error reporting and identify the conditions required /// for a "temporary value dropped here while still borrowed" error. See #45360. - storage_drop_or_dead_error_reported: FxHashSet, + storage_dead_or_drop_error_reported: FxHashSet, } // (forced to be `pub` due to its use as an associated type below.) @@ -296,15 +296,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx } StatementKind::StorageDead(local) => { - if !self.storage_drop_or_dead_error_reported.contains(&local) { - let error_reported = self.access_lvalue(ContextKind::StorageDead.new(location), - (&Lvalue::Local(local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state); - - if error_reported { - self.storage_drop_or_dead_error_reported.insert(local); - } - } + self.access_lvalue(ContextKind::StorageDead.new(location), + (&Lvalue::Local(local), span), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state); } } } @@ -523,9 +517,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context: Context, lvalue_span: (&Lvalue<'tcx>, Span), kind: (ShallowOrDeep, ReadOrWrite), - flow_state: &InProgress<'cx, 'gcx, 'tcx>) -> bool { + flow_state: &InProgress<'cx, 'gcx, 'tcx>) { let (sd, rw) = kind; + let storage_dead_or_drop_local = match (lvalue_span.0, rw) { + (&Lvalue::Local(local), Write(WriteKind::StorageDeadOrDrop)) => Some(local), + _ => None + }; + + // Check if error has already been reported to stop duplicate reporting. + if let Some(local) = storage_dead_or_drop_local { + if self.storage_dead_or_drop_error_reported.contains(&local) { + return; + } + } + // Check permissions self.check_access_permissions(lvalue_span, rw); @@ -590,7 +596,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } }); - error_reported + + if error_reported { + if let Some(local) = storage_dead_or_drop_local { + self.storage_dead_or_drop_error_reported.insert(local); + } + } } fn mutate_lvalue(&mut self, @@ -708,39 +719,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, '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); - // Check if error has already been reported to stop duplicate reporting. - let has_storage_drop_or_dead_error_reported = match *lvalue { - Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.contains(&local), - _ => false, - }; - - // If the error has been reported already, then we don't need the access_lvalue call. - if !has_storage_drop_or_dead_error_reported || consume_via_drop != ConsumeKind::Drop { - let error_reported; - - 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 - error_reported = 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) - error_reported = self.access_lvalue(context, lvalue_span, - (Deep, Read(ReadKind::Copy)), flow_state); - } + if moves_by_default { + let kind = match consume_via_drop { + ConsumeKind::Drop => WriteKind::StorageDeadOrDrop, + _ => WriteKind::Move, + }; - // If there was an error, then we keep track of it so as to deduplicate it. - // We only do this on ConsumeKind::Drop. - if error_reported && consume_via_drop == ConsumeKind::Drop { - if let Lvalue::Local(local) = *lvalue { - self.storage_drop_or_dead_error_reported.insert(local); - } - } + // 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. From 73f5bab33fa890d265dec99d7c465ad9871ffe7d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 27 Nov 2017 21:01:30 +0200 Subject: [PATCH 2/6] rustc_mir: enforce that arguments are replaced with Local's only. --- src/librustc_mir/transform/inline.rs | 55 +++++++--------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 35cade25f77af..bd3662ca7ce34 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>, - callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> { + callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local { let arg = Rvalue::Ref( self.tcx.types.re_erased, BorrowKind::Mut, @@ -539,17 +539,16 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); let cast_tmp = caller_mir.local_decls.push(cast_tmp); - let cast_tmp = Lvalue::Local(cast_tmp); let cast_stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(cast_tmp.clone(), raw_ptr) + kind: StatementKind::Assign(Lvalue::Local(cast_tmp), raw_ptr) }; caller_mir[callsite.bb] .statements.push(cast_stmt); - Operand::Consume(cast_tmp) + cast_tmp } fn make_call_args( @@ -557,7 +556,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>, - ) -> Vec> { + ) -> Vec { let tcx = self.tcx; // There is a bit of a mismatch between the *caller* of a closure and the *callee*. @@ -589,6 +588,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_mir); assert!(args.next().is_none()); + let tuple = Lvalue::Local(tuple); let tuple_tys = if let ty::TyTuple(s, _) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty { s } else { @@ -596,7 +596,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { }; // The `closure_ref` in our example above. - let closure_ref_arg = iter::once(Operand::Consume(self_)); + let closure_ref_arg = iter::once(self_); // The `tmp0`, `tmp1`, and `tmp2` in our example abonve. let tuple_tmp_args = @@ -605,14 +605,13 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let tuple_field = Operand::Consume(tuple.clone().field(Field::new(i), ty)); // Spill to a local to make e.g. `tmp0`. - let tmp = self.create_temp_if_necessary(tuple_field, callsite, caller_mir); - Operand::Consume(tmp) + self.create_temp_if_necessary(tuple_field, callsite, caller_mir) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| Operand::Consume(self.create_temp_if_necessary(a, callsite, caller_mir))) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_mir)) .collect() } } @@ -624,14 +623,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { arg: Operand<'tcx>, callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>, - ) -> Lvalue<'tcx> { + ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. if let Operand::Consume(Lvalue::Local(local)) = arg { if caller_mir.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already - return Lvalue::Local(local); + return local; } } @@ -643,11 +642,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); let arg_tmp = caller_mir.local_decls.push(arg_tmp); - let arg_tmp = Lvalue::Local(arg_tmp); let stmt = Statement { source_info: callsite.location, - kind: StatementKind::Assign(arg_tmp.clone(), arg), + kind: StatementKind::Assign(Lvalue::Local(arg_tmp), arg), }; caller_mir[callsite.bb].statements.push(stmt); arg_tmp @@ -693,7 +691,7 @@ fn subst_and_normalize<'a, 'tcx: 'a>( */ struct Integrator<'a, 'tcx: 'a> { block_idx: usize, - args: &'a [Operand<'tcx>], + args: &'a [Local], local_map: IndexVec, scope_map: IndexVec, promoted_map: IndexVec, @@ -710,15 +708,6 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> { debug!("Updating target `{:?}`, new: `{:?}`", tgt, new); new } - - fn arg_index(&self, arg: Local) -> Option { - let idx = arg.index(); - if idx > 0 && idx <= self.args.len() { - Some(idx - 1) - } else { - None - } - } } impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { @@ -737,13 +726,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } let idx = local.index() - 1; if idx < self.args.len() { - match self.args[idx] { - Operand::Consume(Lvalue::Local(l)) => { - *local = l; - return; - }, - ref op => bug!("Arg operand `{:?}` is {:?}, not local", idx, op) - } + *local = self.args[idx]; + return; } *local = self.local_map[Local::new(idx - self.args.len())]; } @@ -760,17 +744,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { } } - fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { - if let Operand::Consume(Lvalue::Local(arg)) = *operand { - if let Some(idx) = self.arg_index(arg) { - let new_arg = self.args[idx].clone(); - *operand = new_arg; - return; - } - } - self.super_operand(operand, location); - } - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { self.in_cleanup_block = data.is_cleanup; self.super_basic_block_data(block, data); From c42a118188e5e0d578b78fff3c3efac548f1944e Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 17 Nov 2017 17:19:57 +0200 Subject: [PATCH 3/6] MIR: split Operand::Consume into Copy and Move. --- src/librustc/ich/impls_mir.rs | 5 +- src/librustc/mir/mod.rs | 21 ++- src/librustc/mir/tcx.rs | 3 +- src/librustc/mir/visit.rs | 18 ++- src/librustc_mir/borrow_check.rs | 148 +++++++----------- src/librustc_mir/build/expr/as_lvalue.rs | 10 +- src/librustc_mir/build/expr/as_operand.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 18 +-- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 2 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/matches/test.rs | 24 +-- src/librustc_mir/build/misc.rs | 12 +- .../dataflow/move_paths/builder.rs | 39 ++--- src/librustc_mir/dataflow/move_paths/mod.rs | 6 +- src/librustc_mir/hair/cx/mod.rs | 4 + src/librustc_mir/shim.rs | 30 ++-- .../transform/add_moves_for_packed_drops.rs | 2 +- src/librustc_mir/transform/add_validation.rs | 10 +- src/librustc_mir/transform/copy_prop.rs | 12 +- src/librustc_mir/transform/elaborate_drops.rs | 4 +- src/librustc_mir/transform/generator.rs | 4 +- src/librustc_mir/transform/inline.rs | 8 +- src/librustc_mir/transform/instcombine.rs | 2 +- src/librustc_mir/transform/lower_128bit.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 13 +- src/librustc_mir/transform/rustc_peek.rs | 5 +- src/librustc_mir/util/elaborate_drops.rs | 31 ++-- src/librustc_mir/util/liveness.rs | 3 +- src/librustc_passes/mir_stats.rs | 3 +- src/librustc_trans/mir/analyze.rs | 17 +- src/librustc_trans/mir/block.rs | 15 +- src/librustc_trans/mir/constant.rs | 5 +- src/librustc_trans/mir/lvalue.rs | 2 +- src/librustc_trans/mir/operand.rs | 3 +- 35 files changed, 251 insertions(+), 238 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d9244c32dc429..e40d07d936bbc 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -420,7 +420,10 @@ impl<'gcx> HashStable> 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) => { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 266f60094c309..d5df90a5ea02c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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>), } @@ -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>(&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) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index d645a00e15781..073f4cafc9dc6 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -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, } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 5f2f5b79cc698..b9db7d236c0d2 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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 | diff --git a/src/librustc_mir/borrow_check.rs b/src/librustc_mir/borrow_check.rs index ef41621c41143..19d121843cbfa 100644 --- a/src/librustc_mir/borrow_check.rs +++ b/src/librustc_mir/borrow_check.rs @@ -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,62 +681,33 @@ 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::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 @@ 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 }; diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 69d0dd992281e..46c15ede4d923 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -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)) } diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index ea6e4342098bc..b9d03cb2d4544 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -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))) } } } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d17f00b489c31..b6f2477a93012 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -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); } } diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index ba422a8183160..a292d8e54980b 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -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); } _ => { diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 3cfb0ff4010da..1878258f90846 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -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() diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b65d859e7d756..fb6458aa115da 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -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), }; diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 02a7bc83f6ee8..b3a46508cf0b2 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -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 } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 1976b70ac0a23..1b689aa2132b4 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -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) + } + } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index af582b8cf66a1..b8a9103c8167c 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -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>, } 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>, Vec>)> { - 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 { .. }) => { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 4703dd8a2afa6..69877367c7688 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -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>)> { - builder::gather_moves(mir, tcx, param_env) + builder::gather_moves(mir, tcx) } } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index b1f4b849b8928..306b41714a553 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -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 { diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 0fa47d8099947..119cd35910fd5 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -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() ) ) diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index 297bc76d472f5..2cb8cb60e07d7 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -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, diff --git a/src/librustc_mir/transform/add_validation.rs b/src/librustc_mir/transform/add_validation.rs index c6f2154eaa471..6021955004e64 100644 --- a/src/librustc_mir/transform/add_validation.rs +++ b/src/librustc_mir/transform/add_validation.rs @@ -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()) }, diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 2966290c2964c..30048639589ff 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -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, } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index c24256cc92cde..6f94bd1f88f14 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -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> { - self.ctxt.drop_flag(path).map(Operand::Consume) + self.ctxt.drop_flag(path).map(Operand::Copy) } } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 43635bcb631b9..fe7ff326f497c 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -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::>()), targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(), diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index bd3662ca7ce34..844459930b8d7 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -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; diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index d66d4b14d693d..b45db18eff5f0 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -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) { diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 9dc5fdadbb195..26621afaba41f 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -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) -} \ No newline at end of file +} diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 97e80de96c5cc..555f0a327980e 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -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. diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 32d4a14c7f757..cc8a6e66da182 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -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, }; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 1852712a08375..bb8dbd64c367e 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -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) diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 4b165a71c81b3..9afd5a1483fbf 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -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); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index ab41ad1e09950..6054d6c24101a 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -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); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 223379527c989..77f607e551435 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -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 | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index f43eba36a8232..61811a62c6630 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -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]); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8c013330e5bcb..e38af774a51ff 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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, 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)) } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 891d52045c217..b7470e470bc14 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -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) diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 8c43bded1bf21..21770c1d79257 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -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) } From 170b88dc79f6ac6e06a00ded1b97395b8a2c6f7a Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 17 Nov 2017 18:07:18 +0200 Subject: [PATCH 4/6] rustc_mir: require that Copy(L) satisfies typeof L: Copy. --- src/librustc_mir/transform/type_check.rs | 29 +++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index ade5cf8b70c2b..6cbc8b7e61987 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -20,7 +20,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeVariants}; use rustc::middle::const_val::ConstVal; use rustc::mir::*; use rustc::mir::tcx::LvalueTy; -use rustc::mir::visit::Visitor; +use rustc::mir::visit::{LvalueContext, Visitor}; use std::fmt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -107,10 +107,10 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn visit_lvalue( &mut self, lvalue: &Lvalue<'tcx>, - _context: visit::LvalueContext, + context: LvalueContext, location: Location, ) { - self.sanitize_lvalue(lvalue, location); + self.sanitize_lvalue(lvalue, location, context); } fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { @@ -164,9 +164,13 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } } - fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> { + fn sanitize_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + location: Location, + context: LvalueContext) + -> LvalueTy<'tcx> { debug!("sanitize_lvalue: {:?}", lvalue); - match *lvalue { + let lvalue_ty = match *lvalue { Lvalue::Local(index) => LvalueTy::Ty { ty: self.mir.local_decls[index].ty, }, @@ -189,7 +193,12 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { LvalueTy::Ty { ty: sty } } Lvalue::Projection(ref proj) => { - let base_ty = self.sanitize_lvalue(&proj.base, location); + let base_context = if context.is_mutating_use() { + LvalueContext::Projection(Mutability::Mut) + } else { + LvalueContext::Projection(Mutability::Not) + }; + let base_ty = self.sanitize_lvalue(&proj.base, location, base_context); if let LvalueTy::Ty { ty } = base_ty { if ty.references_error() { assert!(self.errors_reported); @@ -200,7 +209,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } self.sanitize_projection(base_ty, &proj.elem, lvalue, location) } + }; + if let LvalueContext::Copy = context { + let ty = lvalue_ty.to_ty(self.tcx()); + if self.cx.infcx.type_moves_by_default(self.cx.param_env, ty, DUMMY_SP) { + span_mirbug!(self, lvalue, + "attempted copy of non-Copy type ({:?})", ty); + } } + lvalue_ty } fn sanitize_projection( From 919ed409b0fbb56bcd6c70ff50bfc9275c4b7701 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 17 Nov 2017 18:22:44 +0200 Subject: [PATCH 5/6] tests: update to include move annotations in MIR. --- src/test/mir-opt/basic_assignment.rs | 6 +-- src/test/mir-opt/box_expr.rs | 6 +-- src/test/mir-opt/copy_propagation.rs | 6 +-- src/test/mir-opt/copy_propagation_arg.rs | 14 +++--- src/test/mir-opt/deaggregator_test.rs | 4 +- src/test/mir-opt/deaggregator_test_enum.rs | 4 +- src/test/mir-opt/deaggregator_test_enum_2.rs | 8 ++-- .../mir-opt/deaggregator_test_multiple.rs | 12 ++--- src/test/mir-opt/end_region_2.rs | 2 +- src/test/mir-opt/end_region_3.rs | 2 +- src/test/mir-opt/end_region_4.rs | 2 +- src/test/mir-opt/end_region_5.rs | 6 +-- src/test/mir-opt/end_region_6.rs | 6 +-- src/test/mir-opt/end_region_7.rs | 8 ++-- src/test/mir-opt/end_region_8.rs | 6 +-- src/test/mir-opt/end_region_9.rs | 2 +- src/test/mir-opt/end_region_cyclic.rs | 14 +++--- .../end_region_destruction_extents_1.rs | 8 ++-- .../mir-opt/inline-closure-borrows-arg.rs | 8 ++-- src/test/mir-opt/inline-closure.rs | 8 ++-- src/test/mir-opt/issue-38669.rs | 2 +- src/test/mir-opt/lower_128bit_debug_test.rs | 48 +++++++++---------- src/test/mir-opt/lower_128bit_test.rs | 8 ++-- src/test/mir-opt/match_false_edges.rs | 24 +++++----- .../mir-opt/nll/liveness-drop-intra-block.rs | 2 +- src/test/mir-opt/nll/liveness-interblock.rs | 2 +- src/test/mir-opt/nll/region-liveness-basic.rs | 2 +- .../mir-opt/nll/region-subtyping-basic.rs | 2 +- .../mir-opt/packed-struct-drop-aligned.rs | 8 ++-- .../mir-opt/storage_live_dead_in_statics.rs | 6 +-- src/test/mir-opt/storage_ranges.rs | 2 +- src/test/mir-opt/validate_1.rs | 4 +- src/test/mir-opt/validate_2.rs | 2 +- src/test/mir-opt/validate_3.rs | 2 +- src/test/mir-opt/validate_4.rs | 4 +- src/test/mir-opt/validate_5.rs | 6 +-- 36 files changed, 128 insertions(+), 128 deletions(-) diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index e7263b4739452..a8b87a273bfd5 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -43,14 +43,14 @@ fn main() { // StorageLive(_2); // StorageLive(_3); // _3 = _1; -// _2 = _3; +// _2 = move _3; // StorageDead(_3); // StorageLive(_4); // _4 = std::option::Option>::None; // StorageLive(_5); // StorageLive(_6); -// _6 = _4; -// replace(_5 <- _6) -> [return: bb1, unwind: bb5]; +// _6 = move _4; +// replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // } // bb1: { // drop(_6) -> [return: bb6, unwind: bb4]; diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index c782859b126f0..f4938fae6a5c9 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -46,7 +46,7 @@ impl Drop for S { // } // // bb1: { -// _1 = _2; +// _1 = move _2; // drop(_2) -> bb4; // } // @@ -61,8 +61,8 @@ impl Drop for S { // bb4: { // StorageDead(_2); // StorageLive(_4); -// _4 = _1; -// _3 = const std::mem::drop(_4) -> [return: bb5, unwind: bb7]; +// _4 = move _1; +// _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7]; // } // // bb5: { diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index 223c65737ad60..50d8a5154c449 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -24,10 +24,10 @@ fn main() { // ... // _3 = _1; // ... -// _2 = _3; +// _2 = move _3; // ... // _4 = _2; -// _0 = _4; +// _0 = move _4; // ... // return; // } @@ -35,7 +35,7 @@ fn main() { // START rustc.test.CopyPropagation.after.mir // bb0: { // ... -// _0 = _1; +// _0 = move _1; // ... // return; // } diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs index ae30b5fae88f8..017fac6a6a1a7 100644 --- a/src/test/mir-opt/copy_propagation_arg.rs +++ b/src/test/mir-opt/copy_propagation_arg.rs @@ -43,11 +43,11 @@ fn main() { // StorageLive(_2); // StorageLive(_3); // _3 = _1; -// _2 = const dummy(_3) -> bb1; +// _2 = const dummy(move _3) -> bb1; // } // bb1: { // StorageDead(_3); -// _1 = _2; +// _1 = move _2; // StorageDead(_2); // _0 = (); // return; @@ -58,11 +58,11 @@ fn main() { // StorageLive(_2); // nop; // nop; -// _2 = const dummy(_1) -> bb1; +// _2 = const dummy(move _1) -> bb1; // } // bb1: { // nop; -// _1 = _2; +// _1 = move _2; // StorageDead(_2); // _0 = (); // return; @@ -72,7 +72,7 @@ fn main() { // bb0: { // StorageLive(_3); // _3 = _1; -// _2 = const dummy(_3) -> bb1; +// _2 = const dummy(move _3) -> bb1; // } // bb1: { // StorageDead(_3); @@ -85,7 +85,7 @@ fn main() { // bb0: { // nop; // nop; -// _2 = const dummy(_1) -> bb1; +// _2 = const dummy(move _1) -> bb1; // } // bb1: { // nop; @@ -98,7 +98,7 @@ fn main() { // bb0: { // StorageLive(_2); // _2 = _1; -// _1 = _2; +// _1 = move _2; // StorageDead(_2); // _0 = (); // return; diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index d0f4e3bb60b5a..c918bef129ad1 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -29,7 +29,7 @@ fn main() { // ... // _2 = _1; // ... -// _0 = Baz { x: _2, y: const 0f32, z: const false }; +// _0 = Baz { x: move _2, y: const 0f32, z: const false }; // ... // return; // } @@ -39,7 +39,7 @@ fn main() { // ... // _2 = _1; // ... -// (_0.0: usize) = _2; +// (_0.0: usize) = move _2; // (_0.1: f32) = const 0f32; // (_0.2: bool) = const false; // ... diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs index 9400ae5050ba1..8af56b7c01173 100644 --- a/src/test/mir-opt/deaggregator_test_enum.rs +++ b/src/test/mir-opt/deaggregator_test_enum.rs @@ -30,7 +30,7 @@ fn main() { // bb0: { // StorageLive(_2); // _2 = _1; -// _0 = Baz::Foo { x: _2 }; +// _0 = Baz::Foo { x: move _2 }; // StorageDead(_2); // return; // } @@ -39,7 +39,7 @@ fn main() { // bb0: { // StorageLive(_2); // _2 = _1; -// ((_0 as Foo).0: usize) = _2; +// ((_0 as Foo).0: usize) = move _2; // discriminant(_0) = 1; // StorageDead(_2); // return; diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs index ab62164e80035..b6505de22f3b6 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.rs +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -33,14 +33,14 @@ fn main() { // bb1: { // StorageLive(_4); // _4 = _2; -// _0 = Foo::A(_4,); +// _0 = Foo::A(move _4,); // StorageDead(_4); // goto -> bb3; // } // bb2: { // StorageLive(_5); // _5 = _2; -// _0 = Foo::B(_5,); +// _0 = Foo::B(move _5,); // StorageDead(_5); // goto -> bb3; // } @@ -49,7 +49,7 @@ fn main() { // bb1: { // StorageLive(_4); // _4 = _2; -// ((_0 as A).0: i32) = _4; +// ((_0 as A).0: i32) = move _4; // discriminant(_0) = 0; // StorageDead(_4); // goto -> bb3; @@ -57,7 +57,7 @@ fn main() { // bb2: { // StorageLive(_5); // _5 = _2; -// ((_0 as B).0: i32) = _5; +// ((_0 as B).0: i32) = move _5; // discriminant(_0) = 1; // StorageDead(_5); // goto -> bb3; diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs index 91643e07ed005..3a9a458fd464d 100644 --- a/src/test/mir-opt/deaggregator_test_multiple.rs +++ b/src/test/mir-opt/deaggregator_test_multiple.rs @@ -30,12 +30,12 @@ fn main() { // ... // _3 = _1; // ... -// _2 = Foo::A(_3,); +// _2 = Foo::A(move _3,); // ... // _5 = _1; -// _4 = Foo::A(_5,); +// _4 = Foo::A(move _5,); // ... -// _0 = [_2, _4]; +// _0 = [move _2, move _4]; // ... // return; // } @@ -45,14 +45,14 @@ fn main() { // ... // _3 = _1; // ... -// ((_2 as A).0: i32) = _3; +// ((_2 as A).0: i32) = move _3; // discriminant(_2) = 0; // ... // _5 = _1; -// ((_4 as A).0: i32) = _5; +// ((_4 as A).0: i32) = move _5; // discriminant(_4) = 0; // ... -// _0 = [_2, _4]; +// _0 = [move _2, move _4]; // ... // return; // } diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs index 5ee377569dd16..56c3e2a38a0ed 100644 --- a/src/test/mir-opt/end_region_2.rs +++ b/src/test/mir-opt/end_region_2.rs @@ -46,7 +46,7 @@ fn main() { // _3 = &'23_1rs _2; // StorageLive(_5); // _5 = _2; -// switchInt(_5) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _5) -> [0u8: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs index 1dbbd74cdf3c3..8c0d56eba7828 100644 --- a/src/test/mir-opt/end_region_3.rs +++ b/src/test/mir-opt/end_region_3.rs @@ -48,7 +48,7 @@ fn main() { // _3 = &'26_1rs _1; // StorageLive(_5); // _5 = _1; -// switchInt(_5) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _5) -> [0u8: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs index 6b8018e4b2211..d9456ef1563d3 100644 --- a/src/test/mir-opt/end_region_4.rs +++ b/src/test/mir-opt/end_region_4.rs @@ -51,7 +51,7 @@ fn foo(i: i32) { // _3 = &'26_2rs _2; // StorageLive(_5); // _5 = (*_3); -// _4 = const foo(_5) -> [return: bb1, unwind: bb3]; +// _4 = const foo(move _5) -> [return: bb1, unwind: bb3]; // } // bb1: { // StorageDead(_5); diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs index f5d5bf1e4a64e..c2ee2d62b98e8 100644 --- a/src/test/mir-opt/end_region_5.rs +++ b/src/test/mir-opt/end_region_5.rs @@ -41,9 +41,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // StorageLive(_3); // StorageLive(_4); // _4 = &'14s _1; -// _3 = [closure@NodeId(18)] { d: _4 }; +// _3 = [closure@NodeId(18)] { d: move _4 }; // StorageDead(_4); -// _2 = const foo(_3) -> [return: bb1, unwind: bb3]; +// _2 = const foo(move _3) -> [return: bb1, unwind: bb3]; // } // bb1: { // EndRegion('14s); @@ -73,7 +73,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // bb0: { // StorageLive(_2); // _2 = ((*(_1.0: &'14s D)).0: i32); -// _0 = _2; +// _0 = move _2; // StorageDead(_2); // return; // } diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs index 7f0e16eaa0632..34675e8842f4c 100644 --- a/src/test/mir-opt/end_region_6.rs +++ b/src/test/mir-opt/end_region_6.rs @@ -41,9 +41,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // StorageLive(_3); // StorageLive(_4); // _4 = &'19s _1; -// _3 = [closure@NodeId(22)] { d: _4 }; +// _3 = [closure@NodeId(22)] { d: move _4 }; // StorageDead(_4); -// _2 = const foo(_3) -> [return: bb1, unwind: bb3]; +// _2 = const foo(move _3) -> [return: bb1, unwind: bb3]; // } // bb1: { // EndRegion('19s); @@ -76,7 +76,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _2 = &'15_0rs (*(_1.0: &'19s D)); // StorageLive(_3); // _3 = ((*_2).0: i32); -// _0 = _3; +// _0 = move _3; // StorageDead(_3); // EndRegion('15_0rs); // StorageDead(_2); diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs index 7a17afee3e035..a9b6d2196fc7e 100644 --- a/src/test/mir-opt/end_region_7.rs +++ b/src/test/mir-opt/end_region_7.rs @@ -40,8 +40,8 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _1 = D::{{constructor}}(const 0i32,); // StorageLive(_3); // StorageLive(_4); -// _4 = _1; -// _3 = [closure@NodeId(22)] { d: _4 }; +// _4 = move _1; +// _3 = [closure@NodeId(22)] { d: move _4 }; // drop(_4) -> [return: bb4, unwind: bb3]; // } // bb1: { @@ -55,7 +55,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // } // bb4: { // StorageDead(_4); -// _2 = const foo(_3) -> [return: bb5, unwind: bb3]; +// _2 = const foo(move _3) -> [return: bb5, unwind: bb3]; // } // bb5: { // drop(_3) -> [return: bb6, unwind: bb2]; @@ -84,7 +84,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // _2 = &'15_0rs (_1.0: D); // StorageLive(_3); // _3 = ((*_2).0: i32); -// _0 = _3; +// _0 = move _3; // StorageDead(_3); // EndRegion('15_0rs); // StorageDead(_2); diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs index 1df3099510261..4c1ec4b102629 100644 --- a/src/test/mir-opt/end_region_8.rs +++ b/src/test/mir-opt/end_region_8.rs @@ -46,9 +46,9 @@ fn foo(f: F) where F: FnOnce() -> i32 { // StorageLive(_4); // StorageLive(_5); // _5 = _2; -// _4 = [closure@NodeId(22)] { r: _5 }; +// _4 = [closure@NodeId(22)] { r: move _5 }; // StorageDead(_5); -// _3 = const foo(_4) -> [return: bb1, unwind: bb3]; +// _3 = const foo(move _4) -> [return: bb1, unwind: bb3]; // } // bb1: { // StorageDead(_4); @@ -79,7 +79,7 @@ fn foo(f: F) where F: FnOnce() -> i32 { // bb0: { // StorageLive(_2); // _2 = ((*(_1.0: &'21_1rs D)).0: i32); -// _0 = _2; +// _0 = move _2; // StorageDead(_2); // return; // } diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs index d348207730542..b313e296ac99c 100644 --- a/src/test/mir-opt/end_region_9.rs +++ b/src/test/mir-opt/end_region_9.rs @@ -64,7 +64,7 @@ fn main() { // bb1: { // StorageLive(_7); // _7 = _1; -// switchInt(_7) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _7) -> [0u8: bb3, otherwise: bb2]; // } // bb2: { // _0 = (); diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 5eada97ed20ab..b8dabada18eab 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -70,11 +70,11 @@ fn query() -> bool { true } // StorageLive(_3); // StorageLive(_4); // _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None; -// _3 = const >::new(_4) -> bb2; +// _3 = const >::new(move _4) -> bb2; // } // bb2: { // StorageDead(_4); -// _2 = S<'35_0rs> { r: _3 }; +// _2 = S<'35_0rs> { r: move _3 }; // StorageDead(_3); // StorageLive(_6); // _6 = &'16s (_2.0: std::cell::Cell>>); @@ -83,9 +83,9 @@ fn query() -> bool { true } // StorageLive(_9); // _9 = &'35_0rs _2; // _8 = &'35_0rs (*_9); -// _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(_8,); +// _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,); // StorageDead(_8); -// _5 = const >::set(_6, _7) -> bb3; +// _5 = const >::set(move _6, move _7) -> bb3; // } // bb3: { // EndRegion('16s); @@ -96,7 +96,7 @@ fn query() -> bool { true } // _11 = const query() -> bb4; // } // bb4: { -// switchInt(_11) -> [0u8: bb6, otherwise: bb5]; +// switchInt(move _11) -> [0u8: bb6, otherwise: bb5]; // } // bb5: { // _0 = (); @@ -115,9 +115,9 @@ fn query() -> bool { true } // StorageLive(_17); // _17 = &'35_0rs _2; // _16 = &'35_0rs (*_17); -// _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(_16,); +// _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,); // StorageDead(_16); -// _13 = const >::set(_14, _15) -> bb7; +// _13 = const >::set(move _14, move_15) -> bb7; // } // bb7: { // EndRegion('33s); diff --git a/src/test/mir-opt/end_region_destruction_extents_1.rs b/src/test/mir-opt/end_region_destruction_extents_1.rs index 12d14df47df7d..aebe0a1ff6a91 100644 --- a/src/test/mir-opt/end_region_destruction_extents_1.rs +++ b/src/test/mir-opt/end_region_destruction_extents_1.rs @@ -92,12 +92,12 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // _9 = S1::{{constructor}}(const "dang1",); // _8 = &'10s _9; // _7 = &'10s (*_8); -// _3 = D1<'12ds, '10s>::{{constructor}}(_4, _7); +// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7); // EndRegion('10s); // StorageDead(_7); // StorageDead(_4); // _2 = (_3.0: &'12ds S1); -// _1 = _2; +// _1 = move _2; // StorageDead(_2); // drop(_3) -> bb1; // } @@ -139,12 +139,12 @@ unsafe impl<'a, #[may_dangle] 'b> Drop for D1<'a, 'b> { // StorageLive(_8); // _8 = promoted[0]; // _7 = &'10s (*_8); -// _3 = D1<'12ds, '10s>::{{constructor}}(_4, _7); +// _3 = D1<'12ds, '10s>::{{constructor}}(move _4, move _7); // EndRegion('10s); // StorageDead(_7); // StorageDead(_4); // _2 = (_3.0: &'12ds S1); -// _1 = _2; +// _1 = move _2; // StorageDead(_2); // drop(_3) -> bb1; // } diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index de7b38d551956..3fb54f90984dd 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -37,12 +37,12 @@ fn foo(_t: T, q: &i32) -> i32 { // _6 = &(*_2); // ... // _7 = &(*_2); -// _5 = (_6, _7); -// _9 = (_5.0: &i32); -// _10 = (_5.1: &i32); +// _5 = (move _6, move _7); +// _9 = move (_5.0: &i32); +// _10 = move (_5.1: &i32); // StorageLive(_8); // _8 = (*_9); -// _0 = _8; +// _0 = move _8; // ... // return; // } diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 9d3fb923f5b3a..dc8ff13c03a88 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -33,10 +33,10 @@ fn foo(_t: T, q: i32) -> i32 { // _6 = _2; // ... // _7 = _2; -// _5 = (_6, _7); -// _8 = (_5.0: i32); -// _9 = (_5.1: i32); -// _0 = _8; +// _5 = (move _6, move _7); +// _8 = move (_5.0: i32); +// _9 = move (_5.1: i32); +// _0 = move _8; // ... // return; // } diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 9415e140d8048..b5c188cf834a9 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -31,7 +31,7 @@ fn main() { // bb1: { // StorageLive(_4); // _4 = _1; -// switchInt(_4) -> [0u8: bb3, otherwise: bb2]; +// switchInt(move _4) -> [0u8: bb3, otherwise: bb2]; // } // // bb2: { diff --git a/src/test/mir-opt/lower_128bit_debug_test.rs b/src/test/mir-opt/lower_128bit_debug_test.rs index 4626dc17e1f6e..134a868f933fb 100644 --- a/src/test/mir-opt/lower_128bit_debug_test.rs +++ b/src/test/mir-opt/lower_128bit_debug_test.rs @@ -75,71 +75,71 @@ fn main() { // START rustc.test_signed.Lower128Bit.after.mir // _2 = const i128_addo(_1, const 1i128) -> bb10; // ... -// _1 = (_2.0: i128); +// _1 = move (_2.0: i128); // _3 = const i128_subo(_1, const 2i128) -> bb11; // ... -// _1 = (_3.0: i128); +// _1 = move (_3.0: i128); // _4 = const i128_mulo(_1, const 3i128) -> bb12; // ... -// _1 = (_4.0: i128); +// _1 = move (_4.0: i128); // ... // _1 = const i128_div(_1, const 4i128) -> bb13; // ... // _1 = const i128_rem(_1, const 5i128) -> bb15; // ... -// _1 = (_13.0: i128); +// _1 = move (_13.0: i128); // ... // _17 = const 7i32 as u128 (Misc); -// _14 = const i128_shro(_1, _17) -> bb16; +// _14 = const i128_shro(_1, move _17) -> bb16; // ... -// _1 = (_14.0: i128); +// _1 = move (_14.0: i128); // ... -// assert(!(_2.1: bool), "attempt to add with overflow") -> bb1; +// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // ... -// assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2; +// assert(!move (_3.1: bool), "attempt to subtract with overflow") -> bb2; // ... -// assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3; +// assert(!move (_4.1: bool), "attempt to multiply with overflow") -> bb3; // ... -// assert(!(_13.1: bool), "attempt to shift left with overflow") -> bb8; +// assert(!move (_13.1: bool), "attempt to shift left with overflow") -> bb8; // ... // _16 = const 6i32 as u128 (Misc); -// _13 = const i128_shlo(_1, _16) -> bb14; +// _13 = const i128_shlo(_1, move _16) -> bb14; // ... -// assert(!(_14.1: bool), "attempt to shift right with overflow") -> bb9; +// assert(!move (_14.1: bool), "attempt to shift right with overflow") -> bb9; // END rustc.test_signed.Lower128Bit.after.mir // START rustc.test_unsigned.Lower128Bit.after.mir // _2 = const u128_addo(_1, const 1u128) -> bb8; // ... -// _1 = (_2.0: u128); +// _1 = move (_2.0: u128); // _3 = const u128_subo(_1, const 2u128) -> bb9; // ... -// _1 = (_3.0: u128); +// _1 = move (_3.0: u128); // _4 = const u128_mulo(_1, const 3u128) -> bb10; // ... -// _1 = (_4.0: u128); +// _1 = move (_4.0: u128); // ... // _1 = const u128_div(_1, const 4u128) -> bb11; // ... // _1 = const u128_rem(_1, const 5u128) -> bb13; // ... -// _1 = (_7.0: u128); +// _1 = move (_7.0: u128); // ... // _11 = const 7i32 as u128 (Misc); -// _8 = const u128_shro(_1, _11) -> bb14; +// _8 = const u128_shro(_1, move _11) -> bb14; // ... -// _1 = (_8.0: u128); +// _1 = move (_8.0: u128); // ... -// assert(!(_2.1: bool), "attempt to add with overflow") -> bb1; +// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1; // ... -// assert(!(_3.1: bool), "attempt to subtract with overflow") -> bb2; +// assert(!move (_3.1: bool), "attempt to subtract with overflow") -> bb2; // ... -// assert(!(_4.1: bool), "attempt to multiply with overflow") -> bb3; +// assert(!move (_4.1: bool), "attempt to multiply with overflow") -> bb3; // ... -// assert(!(_7.1: bool), "attempt to shift left with overflow") -> bb6; +// assert(!move (_7.1: bool), "attempt to shift left with overflow") -> bb6; // ... // _10 = const 6i32 as u128 (Misc); -// _7 = const u128_shlo(_1, _10) -> bb12; +// _7 = const u128_shlo(_1, move _10) -> bb12; // ... -// assert(!(_8.1: bool), "attempt to shift right with overflow") -> bb7; +// assert(!move (_8.1: bool), "attempt to shift right with overflow") -> bb7; // END rustc.test_unsigned.Lower128Bit.after.mir diff --git a/src/test/mir-opt/lower_128bit_test.rs b/src/test/mir-opt/lower_128bit_test.rs index 207cd0ac57eb0..5de75014f0efb 100644 --- a/src/test/mir-opt/lower_128bit_test.rs +++ b/src/test/mir-opt/lower_128bit_test.rs @@ -83,10 +83,10 @@ fn main() { // _1 = const i128_sub(_1, const 2i128) -> bb6; // ... // _11 = const 7i32 as u32 (Misc); -// _1 = const i128_shr(_1, _11) -> bb9; +// _1 = const i128_shr(_1, move _11) -> bb9; // ... // _12 = const 6i32 as u32 (Misc); -// _1 = const i128_shl(_1, _12) -> bb10; +// _1 = const i128_shl(_1, move _12) -> bb10; // END rustc.test_signed.Lower128Bit.after.mir // START rustc.test_unsigned.Lower128Bit.after.mir @@ -101,8 +101,8 @@ fn main() { // _1 = const u128_sub(_1, const 2u128) -> bb4; // ... // _5 = const 7i32 as u32 (Misc); -// _1 = const u128_shr(_1, _5) -> bb7; +// _1 = const u128_shr(_1, move _5) -> bb7; // ... // _6 = const 6i32 as u32 (Misc); -// _1 = const u128_shl(_1, _6) -> bb8; +// _1 = const u128_shl(_1, move _6) -> bb8; // END rustc.test_unsigned.Lower128Bit.after.mir diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index a59b21473f1e3..b0adbd6ba89e6 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -54,12 +54,12 @@ fn main() { // ... // _2 = std::option::Option::Some(const 42i32,); // _5 = discriminant(_2); -// switchInt(_5) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; +// switchInt(move _5) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; // } // bb1: { // arm1 // StorageLive(_7); // _7 = _3; -// _1 = (const 1i32, _7); +// _1 = (const 1i32, move _7); // StorageDead(_7); // goto -> bb12; // } @@ -89,7 +89,7 @@ fn main() { // _6 = const guard() -> bb9; // } // bb9: { // end of guard -// switchInt(_6) -> [0u8: bb10, otherwise: bb1]; +// switchInt(move _6) -> [0u8: bb10, otherwise: bb1]; // } // bb10: { // to pre_binding2 // falseEdges -> [real: bb4, imaginary: bb4]; @@ -99,7 +99,7 @@ fn main() { // _4 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _4; -// _1 = (const 2i32, _8); +// _1 = (const 2i32, move _8); // StorageDead(_8); // goto -> bb12; // } @@ -114,12 +114,12 @@ fn main() { // ... // _2 = std::option::Option::Some(const 42i32,); // _5 = discriminant(_2); -// switchInt(_5) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; +// switchInt(move _5) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; // } // bb1: { // arm1 // StorageLive(_7); // _7 = _3; -// _1 = (const 1i32, _7); +// _1 = (const 1i32, move _7); // StorageDead(_7); // goto -> bb12; // } @@ -149,7 +149,7 @@ fn main() { // _6 = const guard() -> bb9; // } // bb9: { // end of guard -// switchInt(_6) -> [0u8: bb10, otherwise: bb1]; +// switchInt(move _6) -> [0u8: bb10, otherwise: bb1]; // } // bb10: { // to pre_binding2 // falseEdges -> [real: bb5, imaginary: bb4]; @@ -159,7 +159,7 @@ fn main() { // _4 = ((_2 as Some).0: i32); // StorageLive(_8); // _8 = _4; -// _1 = (const 2i32, _8); +// _1 = (const 2i32, move _8); // StorageDead(_8); // goto -> bb12; // } @@ -174,7 +174,7 @@ fn main() { // ... // _2 = std::option::Option::Some(const 1i32,); // _7 = discriminant(_2); -// switchInt(_7) -> [1isize: bb3, otherwise: bb4]; +// switchInt(move _7) -> [1isize: bb3, otherwise: bb4]; // } // bb1: { // arm1 // _1 = const 1i32; @@ -207,7 +207,7 @@ fn main() { // _8 = const guard() -> bb9; // } // bb9: { //end of guard -// switchInt(_8) -> [0u8: bb10, otherwise: bb1]; +// switchInt(move _8) -> [0u8: bb10, otherwise: bb1]; // } // bb10: { // to pre_binding2 // falseEdges -> [real: bb4, imaginary: bb4]; @@ -224,11 +224,11 @@ fn main() { // StorageLive(_10); // StorageLive(_11); // _11 = _5; -// _10 = const guard2(_11) -> bb13; +// _10 = const guard2(move _11) -> bb13; // } // bb13: { // end of guard2 // StorageDead(_11); -// switchInt(_10) -> [0u8: bb14, otherwise: bb2]; +// switchInt(move _10) -> [0u8: bb14, otherwise: bb2]; // } // bb14: { // to pre_binding4 // falseEdges -> [real: bb6, imaginary: bb6]; diff --git a/src/test/mir-opt/nll/liveness-drop-intra-block.rs b/src/test/mir-opt/nll/liveness-drop-intra-block.rs index 5c34479d25958..3e86677956f0b 100644 --- a/src/test/mir-opt/nll/liveness-drop-intra-block.rs +++ b/src/test/mir-opt/nll/liveness-drop-intra-block.rs @@ -36,6 +36,6 @@ fn main() { // | Live variables at bb1[3]: [_1] // _4 = _1; // | Live variables at bb1[4]: [_4] -// _3 = const use_x(_4) -> bb2; +// _3 = const use_x(move _4) -> bb2; // } // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/liveness-interblock.rs b/src/test/mir-opt/nll/liveness-interblock.rs index 8217befca6bd5..32a38a5cd5e35 100644 --- a/src/test/mir-opt/nll/liveness-interblock.rs +++ b/src/test/mir-opt/nll/liveness-interblock.rs @@ -36,7 +36,7 @@ fn main() { // | Live variables at bb2[1]: [_1] // _4 = _1; // | Live variables at bb2[2]: [_4] -// _3 = const make_live(_4) -> bb4; +// _3 = const make_live(move _4) -> bb4; // } // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-liveness-basic.rs b/src/test/mir-opt/nll/region-liveness-basic.rs index ae059febc7109..3aba3ac86aea4 100644 --- a/src/test/mir-opt/nll/region-liveness-basic.rs +++ b/src/test/mir-opt/nll/region-liveness-basic.rs @@ -51,6 +51,6 @@ fn main() { // | Live variables at bb2[1]: [_2] // _7 = (*_2); // | Live variables at bb2[2]: [_7] -// _6 = const use_x(_7) -> bb4; +// _6 = const use_x(move _7) -> bb4; // } // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index fb178b46b470e..3570107673052 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -45,5 +45,5 @@ fn main() { // ... // _7 = _2; // ... -// _6 = _7; +// _6 = move _7; // END rustc.main.nll.0.mir diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 07a943976c3b8..dc36248811ee5 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -40,10 +40,10 @@ impl Drop for Droppy { // bb0: { // StorageLive(_1); // ... -// _1 = Packed::{{constructor}}(_2,); +// _1 = Packed::{{constructor}}(move _2,); // ... // StorageLive(_6); -// _6 = (_1.0: Aligned); +// _6 = move (_1.0: Aligned); // drop(_6) -> [return: bb4, unwind: bb3]; // } // bb1: { @@ -54,12 +54,12 @@ impl Drop for Droppy { // return; // } // bb3: { -// (_1.0: Aligned) = _4; +// (_1.0: Aligned) = move _4; // drop(_1) -> bb1; // } // bb4: { // StorageDead(_6); -// (_1.0: Aligned) = _4; +// (_1.0: Aligned) = move _4; // StorageDead(_4); // _0 = (); // drop(_1) -> bb2; diff --git a/src/test/mir-opt/storage_live_dead_in_statics.rs b/src/test/mir-opt/storage_live_dead_in_statics.rs index 995639e20d67d..730ef655b13d0 100644 --- a/src/test/mir-opt/storage_live_dead_in_statics.rs +++ b/src/test/mir-opt/storage_live_dead_in_statics.rs @@ -185,11 +185,11 @@ fn main() { // _47 = (const 0u32, const 2u32); // StorageLive(_48); // _48 = (const 0u32, const 3u32); -// _6 = [_7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48]; +// _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // _5 = &_6; // _4 = &(*_5); -// _3 = _4 as &'static [(u32, u32)] (Unsize); -// _2 = Foo { tup: const "hi", data: _3 }; +// _3 = move _4 as &'static [(u32, u32)] (Unsize); +// _2 = Foo { tup: const "hi", data: move _3 }; // _1 = &_2; // _0 = &(*_1); // StorageDead(_1); diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index 53cb82bb0f674..41eaf67d292a6 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -27,7 +27,7 @@ fn main() { // StorageLive(_4); // StorageLive(_5); // _5 = _1; -// _4 = std::option::Option::Some(_5,); +// _4 = std::option::Option::Some(move _5,); // StorageDead(_5); // _3 = &_4; // _2 = (); diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index b7360a0e08733..e6cd535500055 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -47,7 +47,7 @@ fn main() { // _5 = &ReErased mut (*_6); // Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(10)))]); // Validate(Release, [_2: (), _3: &ReScope(Node(ItemLocalId(10))) Test, _5: &ReScope(Node(ItemLocalId(10))) mut i32]); -// _2 = const Test::foo(_3, _5) -> bb1; +// _2 = const Test::foo(move _3, move _5) -> bb1; // } // // bb1: { @@ -69,7 +69,7 @@ fn main() { // Validate(Acquire, [(*_3): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 })) (imm)]); // StorageLive(_4); // _4 = (*_3); -// _0 = _4; +// _0 = move _4; // StorageDead(_4); // EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(22), first_statement_index: 0 }))); // StorageDead(_3); diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 5f3dad5efde15..5b8ba4d8d0632 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -22,7 +22,7 @@ fn main() { // bb1: { // Validate(Acquire, [_2: std::boxed::Box<[i32; 3]>]); // Validate(Release, [_2: std::boxed::Box<[i32; 3]>]); -// _1 = _2 as std::boxed::Box<[i32]> (Unsize); +// _1 = move _2 as std::boxed::Box<[i32]> (Unsize); // Validate(Acquire, [_1: std::boxed::Box<[i32]>]); // StorageDead(_2); // StorageDead(_3); diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 50c410039e2c5..80e75fcee8ac4 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -48,7 +48,7 @@ fn main() { // _4 = &ReErased (*_5); // Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(17))) (imm)]); // Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(17))) i32]); -// _3 = const foo(_4) -> bb1; +// _3 = const foo(move _4) -> bb1; // } // bb1: { // Validate(Acquire, [_3: ()]); diff --git a/src/test/mir-opt/validate_4.rs b/src/test/mir-opt/validate_4.rs index 39438af4b449a..fb0c8871d8384 100644 --- a/src/test/mir-opt/validate_4.rs +++ b/src/test/mir-opt/validate_4.rs @@ -65,7 +65,7 @@ fn main() { // Validate(Acquire, [_1: &ReFree(DefId(0/0:4 ~ validate_4[317d]::test[0]), BrAnon(0)) mut i32]); // Validate(Release, [_1: &ReFree(DefId(0/0:4 ~ validate_4[317d]::test[0]), BrAnon(0)) mut i32]); // ... -// _2 = const write_42(_3) -> bb1; +// _2 = const write_42(move _3) -> bb1; // } // bb1: { // Validate(Acquire, [_2: bool]); @@ -82,7 +82,7 @@ fn main() { // Validate(Release, [_1: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId(0/1:10 ~ validate_4[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]); // StorageLive(_3); // ... -// _0 = const write_42(_3) -> bb1; +// _0 = const write_42(move _3) -> bb1; // } // ... // } diff --git a/src/test/mir-opt/validate_5.rs b/src/test/mir-opt/validate_5.rs index 043338c808983..c9408c1f2f88b 100644 --- a/src/test/mir-opt/validate_5.rs +++ b/src/test/mir-opt/validate_5.rs @@ -40,7 +40,7 @@ fn main() { // Validate(Acquire, [_1: &ReFree(DefId(0/0:4 ~ validate_5[317d]::test[0]), BrAnon(0)) mut i32]); // ... // Validate(Release, [_2: bool, _3: *mut i32]); -// _2 = const write_42(_3) -> bb1; +// _2 = const write_42(move _3) -> bb1; // } // ... // } @@ -55,11 +55,11 @@ fn main() { // Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]); // _4 = &ReErased mut (*_2); // Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(9)))]); -// _3 = _4 as *mut i32 (Misc); +// _3 = move _4 as *mut i32 (Misc); // EndRegion(ReScope(Node(ItemLocalId(9)))); // StorageDead(_4); // Validate(Release, [_0: bool, _3: *mut i32]); -// _0 = const write_42(_3) -> bb1; +// _0 = const write_42(move _3) -> bb1; // } // ... // } From 69b5139fdeeeaed15519cdfd55e2fe53b59c7531 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 28 Nov 2017 08:24:38 +0200 Subject: [PATCH 6/6] rustc_mir: implement an "lvalue reuse" optimization (aka destination propagation aka NRVO). --- src/librustc_mir/transform/mod.rs | 2 + src/librustc_mir/transform/reuse_lvalues.rs | 288 ++++++++++++++++++ src/test/codegen/align-struct.rs | 3 + src/test/codegen/zip.rs | 2 +- src/test/mir-opt/copy_propagation.rs | 9 +- .../mir-opt/inline-closure-borrows-arg.rs | 8 +- src/test/mir-opt/inline-closure.rs | 2 +- 7 files changed, 301 insertions(+), 13 deletions(-) create mode 100644 src/librustc_mir/transform/reuse_lvalues.rs diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 418d3d220581e..43fa04c6b3546 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -44,6 +44,7 @@ pub mod generator; pub mod inline; pub mod nll; pub mod lower_128bit; +pub mod reuse_lvalues; pub(crate) fn provide(providers: &mut Providers) { self::qualify_consts::provide(providers); @@ -254,6 +255,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx inline::Inline, instcombine::InstCombine, deaggregator::Deaggregator, + reuse_lvalues::ReuseLvalues, copy_prop::CopyPropagation, simplify::SimplifyLocals, diff --git a/src/librustc_mir/transform/reuse_lvalues.rs b/src/librustc_mir/transform/reuse_lvalues.rs new file mode 100644 index 0000000000000..8d9ff1b674e05 --- /dev/null +++ b/src/librustc_mir/transform/reuse_lvalues.rs @@ -0,0 +1,288 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A pass that reuses "final destinations" of values, +//! propagating the lvalue back through a chain of moves. + +use rustc::hir; +use rustc::mir::*; +use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; +use rustc::session::config::FullDebugInfo; +use rustc::ty::TyCtxt; +use transform::{MirPass, MirSource}; + +use rustc_data_structures::indexed_vec::IndexVec; + +pub struct ReuseLvalues; + +impl MirPass for ReuseLvalues { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>) { + // Don't run on constant MIR, because trans might not be able to + // evaluate the modified MIR. + // FIXME(eddyb) Remove check after miri is merged. + let id = tcx.hir.as_local_node_id(source.def_id).unwrap(); + match (tcx.hir.body_owner_kind(id), source.promoted) { + (_, Some(_)) | + (hir::BodyOwnerKind::Const, _) | + (hir::BodyOwnerKind::Static(_), _) => return, + + (hir::BodyOwnerKind::Fn, _) => { + if tcx.is_const_fn(source.def_id) { + // Don't run on const functions, as, again, trans might not be able to evaluate + // the optimized IR. + return + } + } + } + + // FIXME(eddyb) We should allow multiple user variables + // per local for debuginfo instead of not optimizing. + if tcx.sess.opts.debuginfo == FullDebugInfo { + return; + } + + // Collect the def and move information for all locals. + let mut collector = DefMoveCollector { + defs_moves: IndexVec::from_elem((Def::Never, Move::Never), &mir.local_decls), + }; + for arg in mir.args_iter() { + // Arguments are special because they're initialized + // in callers, and the collector doesn't know this. + collector.defs_moves[arg].0 = Def::Other; + } + collector.visit_mir(mir); + let mut defs_moves = collector.defs_moves; + + // Keep only locals with a clear initialization and move, + // as they are guaranteed to have all accesses in between. + // Also, the destination local of the move has to also have + // a single initialization (the move itself), otherwise + // there could be accesses that overlap the move chain. + for local in mir.local_decls.indices() { + let (def, mov) = defs_moves[local]; + if let Move::Into(dest) = mov { + if let Def::Once { .. } = def { + if let (Def::Once { ref mut reused }, _) = defs_moves[dest] { + *reused = true; + continue; + } + } + + // Failed to confirm the destination. + defs_moves[local].1 = Move::Other; + } + } + + // Apply the appropriate replacements. + let mut replacer = Replacer { + defs_moves + }; + replacer.visit_mir(mir); + } +} + +/// How (many times) was a local written? +/// Note that borrows are completely ignored, +/// as they get invalidated by moves regardless. +#[derive(Copy, Clone, Debug)] +enum Def { + /// No writes to this local. + Never, + + /// Only one direct initialization, from `Assign` or `Call`. + /// + /// If `reused` is `true`, this local is a destination + /// in a chain of moves and should have all of its + /// `StorageLive` statements removed. + Once { + reused: bool + }, + + /// Any other number or kind of mutating accesses. + Other, +} + +/// How (many times) was a local moved? +#[derive(Copy, Clone, Debug)] +enum Move { + /// No moves of this local. + Never, + + /// Only one move, assigning another local. + /// + /// Ends up replaced by its destination and should + /// have all of its `StorageDead` statements removed. + Into(Local), + + /// Any other number or kind of moves. + Other, +} + + +struct DefMoveCollector { + defs_moves: IndexVec, +} + +impl<'tcx> Visitor<'tcx> for DefMoveCollector { + fn visit_local(&mut self, + &local: &Local, + context: LvalueContext<'tcx>, + _location: Location) { + let (ref mut def, ref mut mov) = self.defs_moves[local]; + match context { + // We specifically want the first direct initialization. + LvalueContext::Store | + LvalueContext::Call => { + if let Def::Never = *def { + *def = Def::Once { reused: false }; + } else { + *def = Def::Other; + } + } + + // Initialization of a field or similar. + LvalueContext::Projection(Mutability::Mut) => { + *def = Def::Other; + } + + // Both of these count as moved, and not the kind + // we want for `Move::Into` (see `visit_assign`). + LvalueContext::Drop | + LvalueContext::Move => *mov = Move::Other, + + // We can ignore everything else. + LvalueContext::Inspect | + LvalueContext::Copy | + LvalueContext::Projection(Mutability::Not) | + LvalueContext::Borrow { .. } | + LvalueContext::StorageLive | + LvalueContext::StorageDead | + LvalueContext::Validate => {} + } + } + + fn visit_projection(&mut self, + proj: &LvalueProjection<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + // Pretend derefs copy the underlying pointer, as we don't + // need to treat the base local as being mutated or moved. + let context = if let ProjectionElem::Deref = proj.elem { + LvalueContext::Copy + } else { + match context { + // Pass down the kinds of contexts for which we don't + // need to disambigutate between direct and projected. + LvalueContext::Borrow { .. } | + LvalueContext::Copy | + LvalueContext::Move | + LvalueContext::Drop => context, + + _ if context.is_mutating_use() => { + LvalueContext::Projection(Mutability::Mut) + } + _ => { + LvalueContext::Projection(Mutability::Not) + } + } + }; + self.visit_lvalue(&proj.base, context, location); + self.visit_projection_elem(&proj.elem, context, location); + } + + fn visit_assign(&mut self, + _: BasicBlock, + lvalue: &Lvalue<'tcx>, + rvalue: &Rvalue<'tcx>, + location: Location) { + self.visit_lvalue(lvalue, LvalueContext::Store, location); + + // Handle `dest = move src`, and skip the `visit_local` + // for `src`, which would always set it to `Move::Other`. + match (lvalue, rvalue) { + (&Lvalue::Local(dest), &Rvalue::Use(Operand::Move(Lvalue::Local(src)))) => { + let (_, ref mut mov) = self.defs_moves[src]; + // We specifically want the first whole move into another local. + if let Move::Never = *mov { + *mov = Move::Into(dest); + } else { + *mov = Move::Other; + } + } + _ => { + self.visit_rvalue(rvalue, location); + } + } + } +} + +struct Replacer { + defs_moves: IndexVec, +} + +impl<'a, 'tcx> MutVisitor<'tcx> for Replacer { + fn visit_local(&mut self, + local: &mut Local, + context: LvalueContext<'tcx>, + location: Location) { + let original = *local; + if let (_, Move::Into(dest)) = self.defs_moves[original] { + *local = dest; + + // Keep going, in case the move chain doesn't stop here. + self.visit_local(local, context, location); + + // Cache the final result, in a similar way to union-find. + let final_dest = *local; + if final_dest != dest { + self.defs_moves[original].1 = Move::Into(final_dest); + } + } + } + + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + // Fuse storage liveness ranges of move chains, by removing + // `StorageLive` of destinations and `StorageDead` of sources. + match statement.kind { + StatementKind::StorageLive(local) | + StatementKind::StorageDead(local) => { + // FIXME(eddyb) We also have to remove `StorageLive` of + // sources and `StorageDead` of destinations to avoid + // creating invalid storage liveness (half-)ranges. + // The proper solution might involve recomputing them. + match self.defs_moves[local] { + (Def::Once { reused: true }, _) | + (_, Move::Into(_)) => { + statement.kind = StatementKind::Nop; + } + _ => {} + } + } + _ => {} + } + + self.super_statement(block, statement, location); + + // Remove self-assignments resulting from replaced move chains. + match statement.kind { + StatementKind::Assign(Lvalue::Local(dest), + Rvalue::Use(Operand::Move(Lvalue::Local(src)))) if dest == src => { + statement.kind = StatementKind::Nop; + } + _ => {} + } + } +} diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index ba81e2d6046e8..b743b55788533 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -15,8 +15,10 @@ #![feature(repr_align)] #[repr(align(64))] +#[derive(Copy, Clone)] pub struct Align64(i32); +#[derive(Copy, Clone)] pub struct Nested64 { a: Align64, b: i32, @@ -24,6 +26,7 @@ pub struct Nested64 { d: i8, } +#[derive(Copy, Clone)] pub enum Enum64 { A(Align64), B(i32), diff --git a/src/test/codegen/zip.rs b/src/test/codegen/zip.rs index d0051c5165fe1..e9088cb0d53cf 100644 --- a/src/test/codegen/zip.rs +++ b/src/test/codegen/zip.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -C no-prepopulate-passes -O +// compile-flags: -O #![crate_type = "lib"] diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index 50d8a5154c449..067a937b0b30c 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -22,12 +22,9 @@ fn main() { // START rustc.test.CopyPropagation.before.mir // bb0: { // ... -// _3 = _1; +// _2 = _1; // ... -// _2 = move _3; -// ... -// _4 = _2; -// _0 = move _4; +// _0 = _2; // ... // return; // } @@ -35,7 +32,7 @@ fn main() { // START rustc.test.CopyPropagation.after.mir // bb0: { // ... -// _0 = move _1; +// _0 = _1; // ... // return; // } diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index 3fb54f90984dd..6ce51be3ec5db 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -38,11 +38,9 @@ fn foo(_t: T, q: &i32) -> i32 { // ... // _7 = &(*_2); // _5 = (move _6, move _7); -// _9 = move (_5.0: &i32); -// _10 = move (_5.1: &i32); -// StorageLive(_8); -// _8 = (*_9); -// _0 = move _8; +// _8 = move (_5.0: &i32); +// _9 = move (_5.1: &i32); +// _0 = (*_8); // ... // return; // } diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index dc8ff13c03a88..22e7de31e90cf 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -36,7 +36,7 @@ fn foo(_t: T, q: i32) -> i32 { // _5 = (move _6, move _7); // _8 = move (_5.0: i32); // _9 = move (_5.1: i32); -// _0 = move _8; +// _0 = _8; // ... // return; // }