Auto merge of #46142 - eddyb:even-mirer-2, r=nikomatsakis
MIR: split Operand::Consume into Copy and Move. By encoding the choice of leaving the source untouched (`Copy`) and invalidating it (`Move`) in MIR, we can express moves of copyable values and have MIR borrow-checking enforce them, *including* ownership transfer of stack locals in calls (when the ABI passes by indirection). Optimizations could turn a "last-use" `Copy` into a `Move`, and the MIR borrow-checker, at least within the confines of safe code, could even do this when the underlying lvalue was borrowed. (However, that last part would be the first time lifetime inference affects code generation, AFAIK). Furthermore, as `Move`s invalidate borrows as well, for any local that is initialized only once, we can ignore borrows that happened before a `Move` and safely reuse/replace its memory storage. This will allow us to perform NRVO in the presence of short-lived borrows, unlike LLVM (currently), and even compute optimal `StorageLive...StorageDead` ranges instead of discarding them.
This commit is contained in:
commit
7745a7a817
|
@ -420,7 +420,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
|
|||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) => {
|
||||
lvalue.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
lvalue.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
|
|
|
@ -1283,7 +1283,17 @@ pub struct VisibilityScopeData {
|
|||
/// being nested in one another.
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Operand<'tcx> {
|
||||
Consume(Lvalue<'tcx>),
|
||||
/// Copy: The value must be available for use afterwards.
|
||||
///
|
||||
/// This implies that the type of the lvalue must be `Copy`; this is true
|
||||
/// by construction during build, but also checked by the MIR type checker.
|
||||
Copy(Lvalue<'tcx>),
|
||||
/// Move: The value (including old borrows of it) will not be used again.
|
||||
///
|
||||
/// Safe for values of all types (modulo future developments towards `?Move`).
|
||||
/// Correct usage patterns are enforced by the borrow checker for safe code.
|
||||
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
|
||||
Move(Lvalue<'tcx>),
|
||||
Constant(Box<Constant<'tcx>>),
|
||||
}
|
||||
|
||||
|
@ -1292,7 +1302,8 @@ impl<'tcx> Debug for Operand<'tcx> {
|
|||
use self::Operand::*;
|
||||
match *self {
|
||||
Constant(ref a) => write!(fmt, "{:?}", a),
|
||||
Consume(ref lv) => write!(fmt, "{:?}", lv),
|
||||
Copy(ref lv) => write!(fmt, "{:?}", lv),
|
||||
Move(ref lv) => write!(fmt, "move {:?}", lv),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2089,14 +2100,16 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
|
|||
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
|
||||
Operand::Copy(ref lval) => Operand::Copy(lval.fold_with(folder)),
|
||||
Operand::Move(ref lval) => Operand::Move(lval.fold_with(folder)),
|
||||
Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
Operand::Consume(ref lval) => lval.visit_with(visitor),
|
||||
Operand::Copy(ref lval) |
|
||||
Operand::Move(ref lval) => lval.visit_with(visitor),
|
||||
Operand::Constant(ref c) => c.visit_with(visitor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,7 +230,8 @@ impl<'tcx> Operand<'tcx> {
|
|||
where D: HasLocalDecls<'tcx>
|
||||
{
|
||||
match self {
|
||||
&Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
|
||||
&Operand::Copy(ref l) |
|
||||
&Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
|
||||
&Operand::Constant(ref c) => c.ty,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -611,8 +611,11 @@ macro_rules! make_mir_visitor {
|
|||
operand: & $($mutability)* Operand<'tcx>,
|
||||
location: Location) {
|
||||
match *operand {
|
||||
Operand::Consume(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Consume, location);
|
||||
Operand::Copy(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Copy, location);
|
||||
}
|
||||
Operand::Move(ref $($mutability)* lvalue) => {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Move, location);
|
||||
}
|
||||
Operand::Constant(ref $($mutability)* constant) => {
|
||||
self.visit_constant(constant, location);
|
||||
|
@ -679,7 +682,7 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
ProjectionElem::Index(ref $($mutability)* local) => {
|
||||
self.visit_local(local, LvalueContext::Consume, location);
|
||||
self.visit_local(local, LvalueContext::Copy, location);
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset: _,
|
||||
min_length: _,
|
||||
|
@ -860,7 +863,8 @@ pub enum LvalueContext<'tcx> {
|
|||
Projection(Mutability),
|
||||
|
||||
// Consumed as part of an operand
|
||||
Consume,
|
||||
Copy,
|
||||
Move,
|
||||
|
||||
// Starting and ending a storage live range
|
||||
StorageLive,
|
||||
|
@ -913,7 +917,8 @@ impl<'tcx> LvalueContext<'tcx> {
|
|||
LvalueContext::Inspect |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
|
||||
LvalueContext::Projection(Mutability::Not) |
|
||||
LvalueContext::Copy | LvalueContext::Move |
|
||||
LvalueContext::StorageLive | LvalueContext::StorageDead |
|
||||
LvalueContext::Validate => false,
|
||||
}
|
||||
|
@ -924,7 +929,8 @@ impl<'tcx> LvalueContext<'tcx> {
|
|||
match *self {
|
||||
LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
|
||||
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
|
||||
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
|
||||
LvalueContext::Projection(Mutability::Not) |
|
||||
LvalueContext::Copy | LvalueContext::Move => true,
|
||||
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
|
||||
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
|
||||
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |
|
||||
|
|
|
@ -25,7 +25,7 @@ use rustc_data_structures::indexed_set::{self, IdxSetBuf};
|
|||
use rustc_data_structures::indexed_vec::{Idx};
|
||||
|
||||
use syntax::ast::{self};
|
||||
use syntax_pos::{DUMMY_SP, Span};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use dataflow::{do_dataflow};
|
||||
use dataflow::{MoveDataParamEnv};
|
||||
|
@ -38,7 +38,6 @@ use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult, M
|
|||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
|
||||
use self::MutateMode::{JustWrite, WriteAndRead};
|
||||
use self::ConsumeKind::{Consume};
|
||||
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
@ -77,7 +76,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
|||
let id = tcx.hir.as_local_node_id(def_id)
|
||||
.expect("do_mir_borrowck: non-local DefId");
|
||||
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx, param_env) {
|
||||
let move_data: MoveData<'tcx> = match MoveData::gather_moves(input_mir, tcx) {
|
||||
Ok(move_data) => move_data,
|
||||
Err((move_data, move_errors)) => {
|
||||
for move_error in move_errors {
|
||||
|
@ -140,7 +139,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 +158,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<Local>,
|
||||
storage_dead_or_drop_error_reported: FxHashSet<Local>,
|
||||
}
|
||||
|
||||
// (forced to be `pub` due to its use as an associated type below.)
|
||||
|
@ -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) => {
|
||||
|
@ -296,15 +298,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -320,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,
|
||||
|
@ -338,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 {
|
||||
|
@ -360,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*/) => {}
|
||||
|
@ -379,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 |
|
||||
|
@ -428,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 }
|
||||
|
||||
|
@ -523,9 +510,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 +589,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,
|
||||
|
@ -637,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) |
|
||||
|
@ -655,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) => {
|
||||
|
@ -669,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -677,83 +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);
|
||||
|
||||
// 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 {
|
||||
Operand::Copy(ref lvalue) => {
|
||||
// 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);
|
||||
}
|
||||
self.access_lvalue(context,
|
||||
(lvalue, span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
flow_state);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
match consume_via_drop {
|
||||
ConsumeKind::Drop => {
|
||||
// If path is merely being dropped, then we'll already
|
||||
// check the drop flag to see if it is moved (thus we
|
||||
// skip this check in that case).
|
||||
}
|
||||
ConsumeKind::Consume => {
|
||||
// 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::Move(ref lvalue) => {
|
||||
// move of lvalue: check if this is move of already borrowed path
|
||||
self.access_lvalue(context,
|
||||
(lvalue, span),
|
||||
(Deep, Write(WriteKind::Move)),
|
||||
flow_state);
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
self.check_if_path_is_moved(context, InitializationRequiringAction::Use,
|
||||
(lvalue, span), flow_state);
|
||||
}
|
||||
Operand::Constant(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1489,22 +1443,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
return None;
|
||||
};
|
||||
|
||||
self.tcx
|
||||
.with_freevars(node_id, |freevars| {
|
||||
for (v, lv) in freevars.iter().zip(lvs) {
|
||||
if let Operand::Consume(Lvalue::Local(l)) = *lv {
|
||||
if local == l {
|
||||
debug!(
|
||||
"find_closure_span: found captured local {:?}",
|
||||
l
|
||||
);
|
||||
return Some(v.span);
|
||||
}
|
||||
self.tcx.with_freevars(node_id, |freevars| {
|
||||
for (v, lv) in freevars.iter().zip(lvs) {
|
||||
match *lv {
|
||||
Operand::Copy(Lvalue::Local(l)) |
|
||||
Operand::Move(Lvalue::Local(l)) if local == l => {
|
||||
debug!(
|
||||
"find_closure_span: found captured local {:?}",
|
||||
l
|
||||
);
|
||||
return Some(v.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
})
|
||||
.map(|var_span| (args_span, var_span))
|
||||
}
|
||||
None
|
||||
}).map(|var_span| (args_span, var_span))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -70,14 +70,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
&len, Rvalue::Len(slice.clone()));
|
||||
this.cfg.push_assign(block, source_info, // lt = idx < len
|
||||
<, Rvalue::BinaryOp(BinOp::Lt,
|
||||
Operand::Consume(Lvalue::Local(idx)),
|
||||
Operand::Consume(len.clone())));
|
||||
Operand::Copy(Lvalue::Local(idx)),
|
||||
Operand::Copy(len.clone())));
|
||||
|
||||
let msg = AssertMessage::BoundsCheck {
|
||||
len: Operand::Consume(len),
|
||||
index: Operand::Consume(Lvalue::Local(idx))
|
||||
len: Operand::Move(len),
|
||||
index: Operand::Copy(Lvalue::Local(idx))
|
||||
};
|
||||
let success = this.assert(block, Operand::Consume(lt), true,
|
||||
let success = this.assert(block, Operand::Move(lt), true,
|
||||
msg, expr_span);
|
||||
success.and(slice.index(idx))
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Category::Rvalue(..) => {
|
||||
let operand =
|
||||
unpack!(block = this.as_temp(block, scope, expr));
|
||||
block.and(Operand::Consume(Lvalue::Local(operand)))
|
||||
block.and(Operand::Move(Lvalue::Local(operand)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Rvalue::BinaryOp(BinOp::Eq, arg.clone(), minval));
|
||||
|
||||
let err = ConstMathErr::Overflow(Op::Neg);
|
||||
block = this.assert(block, Operand::Consume(is_min), false,
|
||||
block = this.assert(block, Operand::Move(is_min), false,
|
||||
AssertMessage::Math(err), expr_span);
|
||||
}
|
||||
block.and(Rvalue::UnaryOp(op, arg))
|
||||
|
@ -117,7 +117,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
// initialize the box contents:
|
||||
unpack!(block = this.into(&Lvalue::Local(result).deref(), block, value));
|
||||
block.and(Rvalue::Use(Operand::Consume(Lvalue::Local(result))))
|
||||
block.and(Rvalue::Use(Operand::Move(Lvalue::Local(result))))
|
||||
}
|
||||
ExprKind::Cast { source } => {
|
||||
let source = this.hir.mirror(source);
|
||||
|
@ -238,7 +238,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
.zip(field_types.into_iter())
|
||||
.map(|(n, ty)| match fields_map.get(&n) {
|
||||
Some(v) => v.clone(),
|
||||
None => Operand::Consume(base.clone().field(n, ty))
|
||||
None => this.consume_by_copy_or_move(base.clone().field(n, ty))
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
|
@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
});
|
||||
|
||||
block = self.assert(block, Operand::Consume(of), false,
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(err), span);
|
||||
|
||||
block.and(Rvalue::Use(Operand::Consume(val)))
|
||||
block.and(Rvalue::Use(Operand::Move(val)))
|
||||
} else {
|
||||
if ty.is_integral() && (op == BinOp::Div || op == BinOp::Rem) {
|
||||
// Checking division and remainder is more complex, since we 1. always check
|
||||
|
@ -348,7 +348,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.cfg.push_assign(block, source_info, &is_zero,
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.clone(), zero));
|
||||
|
||||
block = self.assert(block, Operand::Consume(is_zero), false,
|
||||
block = self.assert(block, Operand::Move(is_zero), false,
|
||||
AssertMessage::Math(zero_err), span);
|
||||
|
||||
// We only need to check for the overflow in one case:
|
||||
|
@ -368,12 +368,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, lhs.clone(), min));
|
||||
|
||||
let is_neg_1 = Operand::Consume(is_neg_1);
|
||||
let is_min = Operand::Consume(is_min);
|
||||
let is_neg_1 = Operand::Move(is_neg_1);
|
||||
let is_min = Operand::Move(is_min);
|
||||
self.cfg.push_assign(block, source_info, &of,
|
||||
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
|
||||
|
||||
block = self.assert(block, Operand::Consume(of), false,
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(overflow_err), span);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
match Category::of(&expr.kind).unwrap() {
|
||||
Category::Lvalue => {
|
||||
let lvalue = unpack!(block = this.as_lvalue(block, expr));
|
||||
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
|
||||
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(lvalue));
|
||||
this.cfg.push_assign(block, source_info, &Lvalue::Local(temp), rvalue);
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -73,7 +73,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// because AssignOp is only legal for Copy types
|
||||
// (overloaded ops should be desugared into a call).
|
||||
let result = unpack!(block = this.build_binary_op(block, op, expr_span, lhs_ty,
|
||||
Operand::Consume(lhs.clone()), rhs));
|
||||
Operand::Copy(lhs.clone()), rhs));
|
||||
this.cfg.push_assign(block, source_info, &lhs, result);
|
||||
|
||||
block.unit()
|
||||
|
|
|
@ -773,7 +773,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
self.schedule_drop_for_binding(binding.var_id, binding.span);
|
||||
let rvalue = match binding.binding_mode {
|
||||
BindingMode::ByValue =>
|
||||
Rvalue::Use(Operand::Consume(binding.source)),
|
||||
Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
|
||||
BindingMode::ByRef(region, borrow_kind) =>
|
||||
Rvalue::Ref(region, borrow_kind, binding.source),
|
||||
};
|
||||
|
|
|
@ -215,7 +215,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
Rvalue::Discriminant(lvalue.clone()));
|
||||
assert_eq!(values.len() + 1, targets.len());
|
||||
self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(discr),
|
||||
discr: Operand::Move(discr),
|
||||
switch_ty: discr_ty,
|
||||
values: From::from(values),
|
||||
targets,
|
||||
|
@ -233,7 +233,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
||||
};
|
||||
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
|
||||
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(lvalue.clone()),
|
||||
true_bb, false_bb))
|
||||
} else {
|
||||
// The switch may be inexhaustive so we
|
||||
|
@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
v.val.to_const_int().expect("switching on integral")
|
||||
).collect();
|
||||
(targets.clone(), TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(lvalue.clone()),
|
||||
discr: Operand::Copy(lvalue.clone()),
|
||||
switch_ty,
|
||||
values: From::from(values),
|
||||
targets,
|
||||
|
@ -259,7 +259,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let mut val = Operand::Consume(lvalue.clone());
|
||||
let mut val = Operand::Copy(lvalue.clone());
|
||||
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type &[u8; N].
|
||||
|
@ -273,7 +273,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let val_slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &val_slice,
|
||||
Rvalue::Cast(CastKind::Unsize, val, ty));
|
||||
val = Operand::Consume(val_slice);
|
||||
val = Operand::Move(val_slice);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -288,7 +288,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let slice = self.temp(ty, test.span);
|
||||
self.cfg.push_assign(block, source_info, &slice,
|
||||
Rvalue::Cast(CastKind::Unsize, array, ty));
|
||||
Operand::Consume(slice)
|
||||
Operand::Move(slice)
|
||||
} else {
|
||||
self.literal_operand(test.span, ty, Literal::Value {
|
||||
value
|
||||
|
@ -322,7 +322,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
let block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(eq_block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(),
|
||||
Operand::Consume(eq_result),
|
||||
Operand::Move(eq_result),
|
||||
block, fail));
|
||||
vec![block, fail]
|
||||
} else {
|
||||
|
@ -335,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
|
||||
let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
|
||||
let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
|
||||
let val = Operand::Consume(lvalue.clone());
|
||||
let val = Operand::Copy(lvalue.clone());
|
||||
|
||||
let fail = self.cfg.start_new_block();
|
||||
let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
|
||||
|
@ -362,14 +362,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// result = actual == expected OR result = actual < expected
|
||||
self.cfg.push_assign(block, source_info, &result,
|
||||
Rvalue::BinaryOp(op,
|
||||
Operand::Consume(actual),
|
||||
Operand::Consume(expected)));
|
||||
Operand::Move(actual),
|
||||
Operand::Move(expected)));
|
||||
|
||||
// branch based on result
|
||||
let (false_bb, true_bb) = (self.cfg.start_new_block(),
|
||||
self.cfg.start_new_block());
|
||||
self.cfg.terminate(block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
|
||||
true_bb, false_bb));
|
||||
vec![true_bb, false_bb]
|
||||
}
|
||||
|
@ -394,7 +394,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
// branch based on result
|
||||
let target_block = self.cfg.start_new_block();
|
||||
self.cfg.terminate(block, source_info,
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Consume(result),
|
||||
TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
|
||||
target_block, fail_block));
|
||||
target_block
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc::ty::{self, Ty};
|
|||
|
||||
use rustc::mir::*;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
/// Add a new temporary value of type `ty` storing the result of
|
||||
|
@ -133,4 +133,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
});
|
||||
temp
|
||||
}
|
||||
|
||||
pub fn consume_by_copy_or_move(&self, lvalue: Lvalue<'tcx>) -> Operand<'tcx> {
|
||||
let tcx = self.hir.tcx();
|
||||
let ty = lvalue.ty(&self.local_decls, tcx).to_ty(tcx);
|
||||
if self.hir.type_moves_by_default(ty, DUMMY_SP) {
|
||||
Operand::Move(lvalue)
|
||||
} else {
|
||||
Operand::Copy(lvalue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ use rustc::mir::tcx::RvalueInitializationState;
|
|||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec};
|
||||
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::mem;
|
||||
|
||||
|
@ -28,16 +26,12 @@ use super::IllegalMoveOriginKind::*;
|
|||
struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
mir: &'a Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
data: MoveData<'tcx>,
|
||||
errors: Vec<MoveError<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
||||
fn new(mir: &'a Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
-> Self {
|
||||
fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
|
||||
let mut move_paths = IndexVec::new();
|
||||
let mut path_map = IndexVec::new();
|
||||
let mut init_path_map = IndexVec::new();
|
||||
|
@ -45,7 +39,6 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
|||
MoveDataBuilder {
|
||||
mir,
|
||||
tcx,
|
||||
param_env,
|
||||
errors: Vec::new(),
|
||||
data: MoveData {
|
||||
moves: IndexVec::new(),
|
||||
|
@ -213,12 +206,10 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
pub(super) fn gather_moves<'a, 'gcx, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<MoveData<'tcx>,
|
||||
(MoveData<'tcx>, Vec<MoveError<'tcx>>)> {
|
||||
let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
|
||||
let mut builder = MoveDataBuilder::new(mir, tcx);
|
||||
|
||||
builder.gather_args();
|
||||
|
||||
|
@ -289,7 +280,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
}
|
||||
StatementKind::StorageLive(_) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.gather_move(&Lvalue::Local(local), true);
|
||||
self.gather_move(&Lvalue::Local(local));
|
||||
}
|
||||
StatementKind::SetDiscriminant{ .. } => {
|
||||
span_bug!(stmt.source_info.span,
|
||||
|
@ -348,7 +339,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
TerminatorKind::Unreachable => { }
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(&Lvalue::Local(RETURN_POINTER), false);
|
||||
self.gather_move(&Lvalue::Local(RETURN_POINTER));
|
||||
}
|
||||
|
||||
TerminatorKind::Assert { .. } |
|
||||
|
@ -361,7 +352,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
|
||||
self.gather_move(location, false);
|
||||
self.gather_move(location);
|
||||
}
|
||||
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
|
||||
self.create_move_path(location);
|
||||
|
@ -383,25 +374,17 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
|
||||
fn gather_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Constant(..) => {} // not-a-move
|
||||
Operand::Consume(ref lval) => { // a move
|
||||
self.gather_move(lval, false);
|
||||
Operand::Constant(..) |
|
||||
Operand::Copy(..) => {} // not-a-move
|
||||
Operand::Move(ref lval) => { // a move
|
||||
self.gather_move(lval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_move(&mut self, lval: &Lvalue<'tcx>, force: bool) {
|
||||
fn gather_move(&mut self, lval: &Lvalue<'tcx>) {
|
||||
debug!("gather_move({:?}, {:?})", self.loc, lval);
|
||||
|
||||
let tcx = self.builder.tcx;
|
||||
let gcx = tcx.global_tcx();
|
||||
let lv_ty = lval.ty(self.builder.mir, tcx).to_ty(tcx);
|
||||
let erased_ty = gcx.lift(&tcx.erase_regions(&lv_ty)).unwrap();
|
||||
if !force && !erased_ty.moves_by_default(gcx, self.builder.param_env, DUMMY_SP) {
|
||||
debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", self.loc, lval, lv_ty);
|
||||
return
|
||||
}
|
||||
|
||||
let path = match self.move_path_for(lval) {
|
||||
Ok(path) | Err(MoveError::UnionMove { path }) => path,
|
||||
Err(error @ MoveError::IllegalMove { .. }) => {
|
||||
|
|
|
@ -293,10 +293,8 @@ impl<'tcx> MoveError<'tcx> {
|
|||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
|
||||
pub fn gather_moves(mir: &Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
param_env: ty::ParamEnv<'gcx>)
|
||||
pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Result<Self, (Self, Vec<MoveError<'tcx>>)> {
|
||||
builder::gather_moves(mir, tcx, param_env)
|
||||
builder::gather_moves(mir, tcx)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,6 +252,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
pub fn check_overflow(&self) -> bool {
|
||||
self.check_overflow
|
||||
}
|
||||
|
||||
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
self.infcx.type_moves_by_default(self.param_env, ty, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
|
||||
|
|
|
@ -385,7 +385,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Use(Operand::Consume(rcvr))
|
||||
Rvalue::Use(Operand::Copy(rcvr))
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
|
@ -448,7 +448,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
// `let loc = Clone::clone(ref_loc);`
|
||||
self.block(vec![statement], TerminatorKind::Call {
|
||||
func,
|
||||
args: vec![Operand::Consume(ref_loc)],
|
||||
args: vec![Operand::Move(ref_loc)],
|
||||
destination: Some((loc.clone(), next)),
|
||||
cleanup: Some(cleanup),
|
||||
}, false);
|
||||
|
@ -470,14 +470,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let compute_cond = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
cond.clone(),
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Consume(end), Operand::Consume(beg))
|
||||
Rvalue::BinaryOp(BinOp::Ne, Operand::Copy(end), Operand::Copy(beg))
|
||||
)
|
||||
);
|
||||
|
||||
// `if end != beg { goto loop_body; } else { goto loop_end; }`
|
||||
self.block(
|
||||
vec![compute_cond],
|
||||
TerminatorKind::if_(tcx, Operand::Consume(cond), loop_body, loop_end),
|
||||
TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
|
||||
is_cleanup
|
||||
);
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
self.make_statement(
|
||||
StatementKind::Assign(
|
||||
ret_field,
|
||||
Rvalue::Use(Operand::Consume(cloned))
|
||||
Rvalue::Use(Operand::Move(cloned))
|
||||
)
|
||||
),
|
||||
self.make_statement(
|
||||
|
@ -555,7 +555,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
Lvalue::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Consume(Lvalue::Local(beg)),
|
||||
Operand::Copy(Lvalue::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
|
@ -568,7 +568,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
let ret_statement = self.make_statement(
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Use(Operand::Consume(ret.clone())),
|
||||
Rvalue::Use(Operand::Move(ret.clone())),
|
||||
)
|
||||
);
|
||||
self.block(vec![ret_statement], TerminatorKind::Return, false);
|
||||
|
@ -611,7 +611,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
Lvalue::Local(beg),
|
||||
Rvalue::BinaryOp(
|
||||
BinOp::Add,
|
||||
Operand::Consume(Lvalue::Local(beg)),
|
||||
Operand::Copy(Lvalue::Local(beg)),
|
||||
Operand::Constant(self.make_usize(1))
|
||||
)
|
||||
)
|
||||
|
@ -666,7 +666,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
|||
Lvalue::Local(RETURN_POINTER),
|
||||
Rvalue::Aggregate(
|
||||
box kind,
|
||||
returns.into_iter().map(Operand::Consume).collect()
|
||||
returns.into_iter().map(Operand::Move).collect()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -705,8 +705,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let mut statements = vec![];
|
||||
|
||||
let rcvr = match rcvr_adjustment {
|
||||
Adjustment::Identity => Operand::Consume(rcvr_l),
|
||||
Adjustment::Deref => Operand::Consume(rcvr_l.deref()),
|
||||
Adjustment::Identity => Operand::Move(rcvr_l),
|
||||
Adjustment::Deref => Operand::Copy(rcvr_l.deref()),
|
||||
Adjustment::RefMut => {
|
||||
// let rcvr = &mut rcvr;
|
||||
let ref_rcvr = local_decls.push(temp_decl(
|
||||
|
@ -724,7 +724,7 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
|
||||
)
|
||||
});
|
||||
Operand::Consume(Lvalue::Local(ref_rcvr))
|
||||
Operand::Move(Lvalue::Local(ref_rcvr))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -750,11 +750,11 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
if let Some(untuple_args) = untuple_args {
|
||||
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
|
||||
let arg_lv = Lvalue::Local(Local::new(1+1));
|
||||
Operand::Consume(arg_lv.field(Field::new(i), *ity))
|
||||
Operand::Move(arg_lv.field(Field::new(i), *ity))
|
||||
}));
|
||||
} else {
|
||||
args.extend((1..sig.inputs().len()).map(|i| {
|
||||
Operand::Consume(Lvalue::Local(Local::new(1+i)))
|
||||
Operand::Move(Lvalue::Local(Local::new(1+i)))
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -868,7 +868,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
|
|||
Rvalue::Aggregate(
|
||||
box AggregateKind::Adt(adt_def, variant_no, substs, None),
|
||||
(1..sig.inputs().len()+1).map(|i| {
|
||||
Operand::Consume(Lvalue::Local(Local::new(i)))
|
||||
Operand::Move(Lvalue::Local(Local::new(i)))
|
||||
}).collect()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -132,7 +132,7 @@ fn add_move_for_packed_drop<'a, 'tcx>(
|
|||
patch.add_statement(
|
||||
loc, StatementKind::StorageLive(temp));
|
||||
patch.add_assign(loc, Lvalue::Local(temp),
|
||||
Rvalue::Use(Operand::Consume(location.clone())));
|
||||
Rvalue::Use(Operand::Move(location.clone())));
|
||||
patch.patch_terminator(loc.block, TerminatorKind::Drop {
|
||||
location: Lvalue::Local(temp),
|
||||
target: storage_dead_block,
|
||||
|
|
|
@ -260,7 +260,8 @@ impl MirPass for AddValidation {
|
|||
.chain(
|
||||
args.iter().filter_map(|op| {
|
||||
match op {
|
||||
&Operand::Consume(ref lval) =>
|
||||
&Operand::Copy(ref lval) |
|
||||
&Operand::Move(ref lval) =>
|
||||
Some(lval_to_operand(lval.clone())),
|
||||
&Operand::Constant(..) => { None },
|
||||
}
|
||||
|
@ -353,14 +354,17 @@ impl MirPass for AddValidation {
|
|||
block_data.statements.insert(i, release_stmt);
|
||||
}
|
||||
// Casts can change what validation does (e.g. unsizing)
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Consume(_), _))
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Copy(_), _)) |
|
||||
StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Move(_), _))
|
||||
if kind != CastKind::Misc =>
|
||||
{
|
||||
// Due to a lack of NLL; we can't capture anything directly here.
|
||||
// Instead, we have to re-match and clone there.
|
||||
let (dest_lval, src_lval) = match block_data.statements[i].kind {
|
||||
StatementKind::Assign(ref dest_lval,
|
||||
Rvalue::Cast(_, Operand::Consume(ref src_lval), _)) =>
|
||||
Rvalue::Cast(_, Operand::Copy(ref src_lval), _)) |
|
||||
StatementKind::Assign(ref dest_lval,
|
||||
Rvalue::Cast(_, Operand::Move(ref src_lval), _)) =>
|
||||
{
|
||||
(dest_lval.clone(), src_lval.clone())
|
||||
},
|
||||
|
|
|
@ -126,7 +126,8 @@ impl MirPass for CopyPropagation {
|
|||
StatementKind::Assign(Lvalue::Local(local), Rvalue::Use(ref operand)) if
|
||||
local == dest_local => {
|
||||
let maybe_action = match *operand {
|
||||
Operand::Consume(ref src_lvalue) => {
|
||||
Operand::Copy(ref src_lvalue) |
|
||||
Operand::Move(ref src_lvalue) => {
|
||||
Action::local_copy(&mir, &def_use_analysis, src_lvalue)
|
||||
}
|
||||
Operand::Constant(ref src_constant) => {
|
||||
|
@ -173,7 +174,11 @@ fn eliminate_self_assignments<'tcx>(
|
|||
match stmt.kind {
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(local),
|
||||
Rvalue::Use(Operand::Consume(Lvalue::Local(src_local))),
|
||||
Rvalue::Use(Operand::Copy(Lvalue::Local(src_local))),
|
||||
) |
|
||||
StatementKind::Assign(
|
||||
Lvalue::Local(local),
|
||||
Rvalue::Use(Operand::Move(Lvalue::Local(src_local))),
|
||||
) if local == dest_local && dest_local == src_local => {}
|
||||
_ => {
|
||||
continue;
|
||||
|
@ -351,7 +356,8 @@ impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> {
|
|||
self.super_operand(operand, location);
|
||||
|
||||
match *operand {
|
||||
Operand::Consume(Lvalue::Local(local)) if local == self.dest_local => {}
|
||||
Operand::Copy(Lvalue::Local(local)) |
|
||||
Operand::Move(Lvalue::Local(local)) if local == self.dest_local => {}
|
||||
_ => return,
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ impl MirPass for ElaborateDrops {
|
|||
_ => return
|
||||
}
|
||||
let param_env = tcx.param_env(src.def_id);
|
||||
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
|
||||
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
|
||||
let elaborate_patch = {
|
||||
let mir = &*mir;
|
||||
let env = MoveDataParamEnv {
|
||||
|
@ -278,7 +278,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> {
|
||||
self.ctxt.drop_flag(path).map(Operand::Consume)
|
||||
self.ctxt.drop_flag(path).map(Operand::Copy)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||
let ret_val = match data.terminator().kind {
|
||||
TerminatorKind::Return => Some((1,
|
||||
None,
|
||||
Operand::Consume(Lvalue::Local(self.new_ret_local)),
|
||||
Operand::Move(Lvalue::Local(self.new_ret_local)),
|
||||
None)),
|
||||
TerminatorKind::Yield { ref value, resume, drop } => Some((0,
|
||||
Some(resume),
|
||||
|
@ -452,7 +452,7 @@ fn insert_switch<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let default_block = insert_term_block(mir, default);
|
||||
|
||||
let switch = TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)),
|
||||
discr: Operand::Copy(transform.make_field(transform.state_field, tcx.types.u32)),
|
||||
switch_ty: tcx.types.u32,
|
||||
values: Cow::from(cases.iter().map(|&(i, _)| ConstInt::U32(i)).collect::<Vec<_>>()),
|
||||
targets: cases.iter().map(|&(_, d)| d).chain(once(default_block)).collect(),
|
||||
|
|
|
@ -456,7 +456,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
|||
// needs to generate the cast.
|
||||
// FIXME: we should probably just generate correct MIR in the first place...
|
||||
|
||||
let arg = if let Operand::Consume(ref lval) = args[0] {
|
||||
let arg = if let Operand::Move(ref lval) = args[0] {
|
||||
lval.clone()
|
||||
} else {
|
||||
bug!("Constant arg to \"box_free\"");
|
||||
|
@ -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,
|
||||
|
@ -535,21 +535,20 @@ 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);
|
||||
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<Operand<'tcx>>,
|
||||
callsite: &CallSite<'tcx>,
|
||||
caller_mir: &mut Mir<'tcx>,
|
||||
) -> Vec<Operand<'tcx>> {
|
||||
) -> Vec<Local> {
|
||||
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,23 +596,22 @@ 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 =
|
||||
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`.
|
||||
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 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 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<Local, Local>,
|
||||
scope_map: IndexVec<VisibilityScope, VisibilityScope>,
|
||||
promoted_map: IndexVec<Promoted, Promoted>,
|
||||
|
@ -710,15 +708,6 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
|
|||
debug!("Updating target `{:?}`, new: `{:?}`", tgt, new);
|
||||
new
|
||||
}
|
||||
|
||||
fn arg_index(&self, arg: Local) -> Option<usize> {
|
||||
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);
|
||||
|
|
|
@ -59,7 +59,7 @@ impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
|
|||
}
|
||||
_ => bug!("Detected `&*` but didn't find `&*`!"),
|
||||
};
|
||||
*rvalue = Rvalue::Use(Operand::Consume(new_lvalue))
|
||||
*rvalue = Rvalue::Use(Operand::Copy(new_lvalue))
|
||||
}
|
||||
|
||||
if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
|
||||
|
|
|
@ -105,7 +105,7 @@ impl Lower128Bit {
|
|||
rhs,
|
||||
rhs_override_ty.unwrap())),
|
||||
});
|
||||
rhs = Operand::Consume(Lvalue::Local(local));
|
||||
rhs = Operand::Move(Lvalue::Local(local));
|
||||
}
|
||||
|
||||
let call_did = check_lang_item_type(
|
||||
|
@ -237,4 +237,4 @@ fn item_for_checked_op(bin_op: BinOp, is_signed: bool) -> Option<(LangItem, RhsK
|
|||
_ => bug!("That should be all the checked ones?"),
|
||||
};
|
||||
Some(i)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,7 +519,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
|
||||
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
|
||||
match *operand {
|
||||
Operand::Consume(ref lvalue) => {
|
||||
Operand::Copy(ref lvalue) |
|
||||
Operand::Move(ref lvalue) => {
|
||||
self.nest(|this| {
|
||||
this.super_operand(operand, location);
|
||||
this.try_consume();
|
||||
|
@ -872,10 +873,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
self.const_fn_arg_vars.insert(index.index()) {
|
||||
|
||||
// Direct use of an argument is permitted.
|
||||
if let Rvalue::Use(Operand::Consume(Lvalue::Local(local))) = *rvalue {
|
||||
if self.mir.local_kind(local) == LocalKind::Arg {
|
||||
return;
|
||||
match *rvalue {
|
||||
Rvalue::Use(Operand::Copy(Lvalue::Local(local))) |
|
||||
Rvalue::Use(Operand::Move(Lvalue::Local(local))) => {
|
||||
if self.mir.local_kind(local) == LocalKind::Arg {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Avoid a generic error for other uses of arguments.
|
||||
|
|
|
@ -45,7 +45,7 @@ impl MirPass for SanityCheck {
|
|||
|
||||
let attributes = tcx.get_attrs(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
let move_data = MoveData::gather_moves(mir, tcx, param_env).unwrap();
|
||||
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
|
||||
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
|
||||
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
|
||||
let flow_inits =
|
||||
|
@ -124,7 +124,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
};
|
||||
assert!(args.len() == 1);
|
||||
let peek_arg_lval = match args[0] {
|
||||
mir::Operand::Consume(ref lval @ mir::Lvalue::Local(_)) => Some(lval),
|
||||
mir::Operand::Copy(ref lval @ mir::Lvalue::Local(_)) |
|
||||
mir::Operand::Move(ref lval @ mir::Lvalue::Local(_)) => Some(lval),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -498,7 +498,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(discr),
|
||||
discr: Operand::Move(discr),
|
||||
switch_ty: discr_ty,
|
||||
values: From::from(values.to_owned()),
|
||||
targets: blocks,
|
||||
|
@ -536,7 +536,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
kind: TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, drop_fn.def_id, substs,
|
||||
self.source_info.span),
|
||||
args: vec![Operand::Consume(Lvalue::Local(ref_lvalue))],
|
||||
args: vec![Operand::Move(Lvalue::Local(ref_lvalue))],
|
||||
destination: Some((unit_temp, succ)),
|
||||
cleanup: unwind.into_option(),
|
||||
},
|
||||
|
@ -572,7 +572,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
ptr_based: bool)
|
||||
-> BasicBlock
|
||||
{
|
||||
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
|
||||
let copy = |lv: &Lvalue<'tcx>| Operand::Copy(lv.clone());
|
||||
let move_ = |lv: &Lvalue<'tcx>| Operand::Move(lv.clone());
|
||||
let tcx = self.tcx();
|
||||
|
||||
let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
|
||||
|
@ -584,14 +585,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
|
||||
let one = self.constant_usize(1);
|
||||
let (ptr_next, cur_next) = if ptr_based {
|
||||
(Rvalue::Use(use_(&Lvalue::Local(cur))),
|
||||
Rvalue::BinaryOp(BinOp::Offset, use_(&Lvalue::Local(cur)), one))
|
||||
(Rvalue::Use(copy(&Lvalue::Local(cur))),
|
||||
Rvalue::BinaryOp(BinOp::Offset, copy(&Lvalue::Local(cur)), one))
|
||||
} else {
|
||||
(Rvalue::Ref(
|
||||
tcx.types.re_erased,
|
||||
BorrowKind::Mut,
|
||||
self.lvalue.clone().index(cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, use_(&Lvalue::Local(cur)), one))
|
||||
Rvalue::BinaryOp(BinOp::Add, copy(&Lvalue::Local(cur)), one))
|
||||
};
|
||||
|
||||
let drop_block = BasicBlockData {
|
||||
|
@ -611,13 +612,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
let loop_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
|
||||
use_(&Lvalue::Local(cur)),
|
||||
use_(length_or_end)))
|
||||
copy(&Lvalue::Local(cur)),
|
||||
copy(length_or_end)))
|
||||
],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
source_info: self.source_info,
|
||||
kind: TerminatorKind::if_(tcx, use_(can_go), succ, drop_block)
|
||||
kind: TerminatorKind::if_(tcx, move_(can_go), succ, drop_block)
|
||||
})
|
||||
};
|
||||
let loop_block = self.elaborator.patch().new_block(loop_block);
|
||||
|
@ -642,14 +643,14 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
|
||||
let tcx = self.tcx();
|
||||
|
||||
let use_ = |lv: &Lvalue<'tcx>| Operand::Consume(lv.clone());
|
||||
let move_ = |lv: &Lvalue<'tcx>| Operand::Move(lv.clone());
|
||||
let size = &Lvalue::Local(self.new_temp(tcx.types.usize));
|
||||
let size_is_zero = &Lvalue::Local(self.new_temp(tcx.types.bool));
|
||||
let base_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
|
||||
self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq,
|
||||
use_(size),
|
||||
move_(size),
|
||||
self.constant_usize(0)))
|
||||
],
|
||||
is_cleanup: self.unwind.is_cleanup(),
|
||||
|
@ -657,7 +658,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
source_info: self.source_info,
|
||||
kind: TerminatorKind::if_(
|
||||
tcx,
|
||||
use_(size_is_zero),
|
||||
move_(size_is_zero),
|
||||
self.drop_loop_pair(ety, false),
|
||||
self.drop_loop_pair(ety, true)
|
||||
)
|
||||
|
@ -718,11 +719,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone()
|
||||
)));
|
||||
drop_block_stmts.push(self.assign(&cur, Rvalue::Cast(
|
||||
CastKind::Misc, Operand::Consume(tmp.clone()), iter_ty
|
||||
CastKind::Misc, Operand::Move(tmp.clone()), iter_ty
|
||||
)));
|
||||
drop_block_stmts.push(self.assign(&length_or_end,
|
||||
Rvalue::BinaryOp(BinOp::Offset,
|
||||
Operand::Consume(cur.clone()), Operand::Consume(length.clone())
|
||||
Operand::Copy(cur.clone()), Operand::Move(length.clone())
|
||||
)));
|
||||
} else {
|
||||
// index = 0 (length already pushed)
|
||||
|
@ -854,7 +855,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
|||
|
||||
let call = TerminatorKind::Call {
|
||||
func: Operand::function_handle(tcx, free_func, substs, self.source_info.span),
|
||||
args: vec![Operand::Consume(self.lvalue.clone())],
|
||||
args: vec![Operand::Move(self.lvalue.clone())],
|
||||
destination: Some((unit_temp, target)),
|
||||
cleanup: None
|
||||
}; // FIXME(#6393)
|
||||
|
|
|
@ -273,7 +273,8 @@ impl<'tcx> Visitor<'tcx> for DefsUsesVisitor {
|
|||
LvalueContext::Borrow { .. } |
|
||||
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Consume |
|
||||
LvalueContext::Copy |
|
||||
LvalueContext::Move |
|
||||
LvalueContext::Validate => {
|
||||
if self.mode.include_regular_use {
|
||||
self.defs_uses.add_use(local);
|
||||
|
|
|
@ -181,7 +181,8 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
|||
location: Location) {
|
||||
self.record("Operand", operand);
|
||||
self.record(match *operand {
|
||||
Operand::Consume(..) => "Operand::Consume",
|
||||
Operand::Copy(..) => "Operand::Copy",
|
||||
Operand::Move(..) => "Operand::Move",
|
||||
Operand::Constant(..) => "Operand::Constant",
|
||||
}, operand);
|
||||
self.super_operand(operand, location);
|
||||
|
|
|
@ -121,7 +121,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||
// box_free(x) shares with `drop x` the property that it
|
||||
// is not guaranteed to be statically dominated by the
|
||||
// definition of x, so x must always be in an alloca.
|
||||
if let mir::Operand::Consume(ref lvalue) = args[0] {
|
||||
if let mir::Operand::Move(ref lvalue) = args[0] {
|
||||
self.visit_lvalue(lvalue, LvalueContext::Drop, location);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,11 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||
|
||||
if let mir::Lvalue::Projection(ref proj) = *lvalue {
|
||||
// Allow uses of projections that are ZSTs or from scalar fields.
|
||||
if let LvalueContext::Consume = context {
|
||||
let is_consume = match context {
|
||||
LvalueContext::Copy | LvalueContext::Move => true,
|
||||
_ => false
|
||||
};
|
||||
if is_consume {
|
||||
let base_ty = proj.base.ty(self.cx.mir, ccx.tcx());
|
||||
let base_ty = self.cx.monomorphize(&base_ty);
|
||||
|
||||
|
@ -154,10 +158,10 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||
if let mir::ProjectionElem::Field(..) = proj.elem {
|
||||
let layout = ccx.layout_of(base_ty.to_ty(ccx.tcx()));
|
||||
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
|
||||
// Recurse as a `Consume` instead of `Projection`,
|
||||
// Recurse with the same context, instead of `Projection`,
|
||||
// potentially stopping at non-operand projections,
|
||||
// which would trigger `mark_as_lvalue` on locals.
|
||||
self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||
self.visit_lvalue(&proj.base, context, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +169,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||
|
||||
// A deref projection only reads the pointer, never needs the lvalue.
|
||||
if let mir::ProjectionElem::Deref = proj.elem {
|
||||
return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
|
||||
return self.visit_lvalue(&proj.base, LvalueContext::Copy, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -184,7 +188,8 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
|||
LvalueContext::StorageLive |
|
||||
LvalueContext::StorageDead |
|
||||
LvalueContext::Validate |
|
||||
LvalueContext::Consume => {}
|
||||
LvalueContext::Copy |
|
||||
LvalueContext::Move => {}
|
||||
|
||||
LvalueContext::Inspect |
|
||||
LvalueContext::Store |
|
||||
|
|
|
@ -517,7 +517,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
// promotes any complex rvalues to constants.
|
||||
if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") {
|
||||
match *arg {
|
||||
mir::Operand::Consume(_) => {
|
||||
mir::Operand::Copy(_) |
|
||||
mir::Operand::Move(_) => {
|
||||
span_bug!(span, "shuffle indices must be constant");
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
|
@ -573,10 +574,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
|
||||
// The callee needs to own the argument memory if we pass it
|
||||
// by-ref, so make a local copy of non-immediate constants.
|
||||
if let (&mir::Operand::Constant(_), Ref(..)) = (arg, op.val) {
|
||||
let tmp = LvalueRef::alloca(&bcx, op.layout, "const");
|
||||
op.val.store(&bcx, tmp);
|
||||
op.val = Ref(tmp.llval, tmp.alignment);
|
||||
match (arg, op.val) {
|
||||
(&mir::Operand::Copy(_), Ref(..)) |
|
||||
(&mir::Operand::Constant(_), Ref(..)) => {
|
||||
let tmp = LvalueRef::alloca(&bcx, op.layout, "const");
|
||||
op.val.store(&bcx, tmp);
|
||||
op.val = Ref(tmp.llval, tmp.alignment);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.trans_argument(&bcx, op, &mut llargs, &fn_ty.args[i]);
|
||||
|
|
|
@ -505,7 +505,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
(Base::Value(llprojected), llextra)
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||
let index = &mir::Operand::Copy(mir::Lvalue::Local(index));
|
||||
let llindex = self.const_operand(index, span)?.llval;
|
||||
|
||||
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
||||
|
@ -540,7 +540,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
|||
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
||||
debug!("const_operand({:?} @ {:?})", operand, span);
|
||||
let result = match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) |
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
Ok(self.const_lvalue(lvalue, span)?.to_const(span))
|
||||
}
|
||||
|
||||
|
|
|
@ -487,7 +487,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
tr_base.project_field(bcx, field.index())
|
||||
}
|
||||
mir::ProjectionElem::Index(index) => {
|
||||
let index = &mir::Operand::Consume(mir::Lvalue::Local(index));
|
||||
let index = &mir::Operand::Copy(mir::Lvalue::Local(index));
|
||||
let index = self.trans_operand(bcx, index);
|
||||
let llindex = index.immediate();
|
||||
tr_base.project_index(bcx, llindex)
|
||||
|
|
|
@ -308,7 +308,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
debug!("trans_operand(operand={:?})", operand);
|
||||
|
||||
match *operand {
|
||||
mir::Operand::Consume(ref lvalue) => {
|
||||
mir::Operand::Copy(ref lvalue) |
|
||||
mir::Operand::Move(ref lvalue) => {
|
||||
self.trans_consume(bcx, lvalue)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::boxed::Box<u32>>::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];
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
// ...
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -41,9 +41,9 @@ fn foo<F>(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: F) where F: FnOnce() -> i32 {
|
|||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = ((*(_1.0: &'14s D)).0: i32);
|
||||
// _0 = _2;
|
||||
// _0 = move _2;
|
||||
// StorageDead(_2);
|
||||
// return;
|
||||
// }
|
||||
|
|
|
@ -41,9 +41,9 @@ fn foo<F>(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: 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);
|
||||
|
|
|
@ -40,8 +40,8 @@ fn foo<F>(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: 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: 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);
|
||||
|
|
|
@ -46,9 +46,9 @@ fn foo<F>(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: F) where F: FnOnce() -> i32 {
|
|||
// bb0: {
|
||||
// StorageLive(_2);
|
||||
// _2 = ((*(_1.0: &'21_1rs D)).0: i32);
|
||||
// _0 = _2;
|
||||
// _0 = move _2;
|
||||
// StorageDead(_2);
|
||||
// return;
|
||||
// }
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -70,11 +70,11 @@ fn query() -> bool { true }
|
|||
// StorageLive(_3);
|
||||
// StorageLive(_4);
|
||||
// _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None;
|
||||
// _3 = const <std::cell::Cell<T>>::new(_4) -> bb2;
|
||||
// _3 = const <std::cell::Cell<T>>::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<std::option::Option<&'35_0rs S<'35_0rs>>>);
|
||||
|
@ -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 <std::cell::Cell<T>>::set(_6, _7) -> bb3;
|
||||
// _5 = const <std::cell::Cell<T>>::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 <std::cell::Cell<T>>::set(_14, _15) -> bb7;
|
||||
// _13 = const <std::cell::Cell<T>>::set(move _14, move_15) -> bb7;
|
||||
// }
|
||||
// bb7: {
|
||||
// EndRegion('33s);
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
|
|
|
@ -37,12 +37,12 @@ fn foo<T: Copy>(_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;
|
||||
// }
|
||||
|
|
|
@ -33,10 +33,10 @@ fn foo<T: Copy>(_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;
|
||||
// }
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -54,12 +54,12 @@ fn main() {
|
|||
// ...
|
||||
// _2 = std::option::Option<i32>::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<i32>::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<i32>::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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -45,5 +45,5 @@ fn main() {
|
|||
// ...
|
||||
// _7 = _2;
|
||||
// ...
|
||||
// _6 = _7;
|
||||
// _6 = move _7;
|
||||
// END rustc.main.nll.0.mir
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
// StorageLive(_4);
|
||||
// StorageLive(_5);
|
||||
// _5 = _1;
|
||||
// _4 = std::option::Option<i32>::Some(_5,);
|
||||
// _4 = std::option::Option<i32>::Some(move _5,);
|
||||
// StorageDead(_5);
|
||||
// _3 = &_4;
|
||||
// _2 = ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: ()]);
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
|
|
|
@ -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;
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
|
|
Loading…
Reference in New Issue