Skip to content

Commit 7745a7a

Browse files
committed
Auto merge of rust-lang#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.
2 parents 3e9a7f7 + 919ed40 commit 7745a7a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+438
-445
lines changed

src/librustc/ich/impls_mir.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for mir::Operand<'gcx> {
420420
mem::discriminant(self).hash_stable(hcx, hasher);
421421

422422
match *self {
423-
mir::Operand::Consume(ref lvalue) => {
423+
mir::Operand::Copy(ref lvalue) => {
424+
lvalue.hash_stable(hcx, hasher);
425+
}
426+
mir::Operand::Move(ref lvalue) => {
424427
lvalue.hash_stable(hcx, hasher);
425428
}
426429
mir::Operand::Constant(ref constant) => {

src/librustc/mir/mod.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,17 @@ pub struct VisibilityScopeData {
12831283
/// being nested in one another.
12841284
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
12851285
pub enum Operand<'tcx> {
1286-
Consume(Lvalue<'tcx>),
1286+
/// Copy: The value must be available for use afterwards.
1287+
///
1288+
/// This implies that the type of the lvalue must be `Copy`; this is true
1289+
/// by construction during build, but also checked by the MIR type checker.
1290+
Copy(Lvalue<'tcx>),
1291+
/// Move: The value (including old borrows of it) will not be used again.
1292+
///
1293+
/// Safe for values of all types (modulo future developments towards `?Move`).
1294+
/// Correct usage patterns are enforced by the borrow checker for safe code.
1295+
/// `Copy` may be converted to `Move` to enable "last-use" optimizations.
1296+
Move(Lvalue<'tcx>),
12871297
Constant(Box<Constant<'tcx>>),
12881298
}
12891299

@@ -1292,7 +1302,8 @@ impl<'tcx> Debug for Operand<'tcx> {
12921302
use self::Operand::*;
12931303
match *self {
12941304
Constant(ref a) => write!(fmt, "{:?}", a),
1295-
Consume(ref lv) => write!(fmt, "{:?}", lv),
1305+
Copy(ref lv) => write!(fmt, "{:?}", lv),
1306+
Move(ref lv) => write!(fmt, "move {:?}", lv),
12961307
}
12971308
}
12981309
}
@@ -2089,14 +2100,16 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
20892100
impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
20902101
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
20912102
match *self {
2092-
Operand::Consume(ref lval) => Operand::Consume(lval.fold_with(folder)),
2103+
Operand::Copy(ref lval) => Operand::Copy(lval.fold_with(folder)),
2104+
Operand::Move(ref lval) => Operand::Move(lval.fold_with(folder)),
20932105
Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
20942106
}
20952107
}
20962108

20972109
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
20982110
match *self {
2099-
Operand::Consume(ref lval) => lval.visit_with(visitor),
2111+
Operand::Copy(ref lval) |
2112+
Operand::Move(ref lval) => lval.visit_with(visitor),
21002113
Operand::Constant(ref c) => c.visit_with(visitor)
21012114
}
21022115
}

src/librustc/mir/tcx.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@ impl<'tcx> Operand<'tcx> {
230230
where D: HasLocalDecls<'tcx>
231231
{
232232
match self {
233-
&Operand::Consume(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
233+
&Operand::Copy(ref l) |
234+
&Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx),
234235
&Operand::Constant(ref c) => c.ty,
235236
}
236237
}

src/librustc/mir/visit.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -611,8 +611,11 @@ macro_rules! make_mir_visitor {
611611
operand: & $($mutability)* Operand<'tcx>,
612612
location: Location) {
613613
match *operand {
614-
Operand::Consume(ref $($mutability)* lvalue) => {
615-
self.visit_lvalue(lvalue, LvalueContext::Consume, location);
614+
Operand::Copy(ref $($mutability)* lvalue) => {
615+
self.visit_lvalue(lvalue, LvalueContext::Copy, location);
616+
}
617+
Operand::Move(ref $($mutability)* lvalue) => {
618+
self.visit_lvalue(lvalue, LvalueContext::Move, location);
616619
}
617620
Operand::Constant(ref $($mutability)* constant) => {
618621
self.visit_constant(constant, location);
@@ -679,7 +682,7 @@ macro_rules! make_mir_visitor {
679682
self.visit_ty(ty, TyContext::Location(location));
680683
}
681684
ProjectionElem::Index(ref $($mutability)* local) => {
682-
self.visit_local(local, LvalueContext::Consume, location);
685+
self.visit_local(local, LvalueContext::Copy, location);
683686
}
684687
ProjectionElem::ConstantIndex { offset: _,
685688
min_length: _,
@@ -860,7 +863,8 @@ pub enum LvalueContext<'tcx> {
860863
Projection(Mutability),
861864

862865
// Consumed as part of an operand
863-
Consume,
866+
Copy,
867+
Move,
864868

865869
// Starting and ending a storage live range
866870
StorageLive,
@@ -913,7 +917,8 @@ impl<'tcx> LvalueContext<'tcx> {
913917
LvalueContext::Inspect |
914918
LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
915919
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
916-
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume |
920+
LvalueContext::Projection(Mutability::Not) |
921+
LvalueContext::Copy | LvalueContext::Move |
917922
LvalueContext::StorageLive | LvalueContext::StorageDead |
918923
LvalueContext::Validate => false,
919924
}
@@ -924,7 +929,8 @@ impl<'tcx> LvalueContext<'tcx> {
924929
match *self {
925930
LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } |
926931
LvalueContext::Borrow { kind: BorrowKind::Unique, .. } |
927-
LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true,
932+
LvalueContext::Projection(Mutability::Not) |
933+
LvalueContext::Copy | LvalueContext::Move => true,
928934
LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store |
929935
LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) |
930936
LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead |

0 commit comments

Comments
 (0)