@@ -25,7 +25,7 @@ use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
25
25
use ty:: fold:: { TypeFoldable , TypeFolder , TypeVisitor } ;
26
26
use util:: ppaux;
27
27
use rustc_back:: slice;
28
- use hir:: InlineAsm ;
28
+ use hir:: { self , InlineAsm } ;
29
29
use std:: ascii;
30
30
use std:: borrow:: { Cow } ;
31
31
use std:: cell:: Ref ;
@@ -818,12 +818,18 @@ pub enum StatementKind<'tcx> {
818
818
/// End the current live range for the storage of the local.
819
819
StorageDead ( Lvalue < ' tcx > ) ,
820
820
821
+ /// Execute a piece of inline Assembly.
821
822
InlineAsm {
822
823
asm : Box < InlineAsm > ,
823
824
outputs : Vec < Lvalue < ' tcx > > ,
824
825
inputs : Vec < Operand < ' tcx > >
825
826
} ,
826
827
828
+ /// Assert the given lvalues to be valid inhabitants of their type. These statements are
829
+ /// currently only interpreted by miri and only generated when "-Z mir-emit-validate" is passed.
830
+ /// See <https://internals.rust-lang.org/t/types-as-contracts/5562/73> for more details.
831
+ Validate ( ValidationOp , Vec < ValidationOperand < ' tcx , Lvalue < ' tcx > > > ) ,
832
+
827
833
/// Mark one terminating point of an extent (i.e. static region).
828
834
/// (The starting point(s) arise implicitly from borrows.)
829
835
EndRegion ( CodeExtent ) ,
@@ -832,13 +838,65 @@ pub enum StatementKind<'tcx> {
832
838
Nop ,
833
839
}
834
840
841
+ /// The `ValidationOp` describes what happens with each of the operands of a
842
+ /// `Validate` statement.
843
+ #[ derive( Copy , Clone , RustcEncodable , RustcDecodable , PartialEq , Eq ) ]
844
+ pub enum ValidationOp {
845
+ /// Recursively traverse the lvalue following the type and validate that all type
846
+ /// invariants are maintained. Furthermore, acquire exclusive/read-only access to the
847
+ /// memory reachable from the lvalue.
848
+ Acquire ,
849
+ /// Recursive traverse the *mutable* part of the type and relinquish all exclusive
850
+ /// access.
851
+ Release ,
852
+ /// Recursive traverse the *mutable* part of the type and relinquish all exclusive
853
+ /// access *until* the given region ends. Then, access will be recovered.
854
+ Suspend ( CodeExtent ) ,
855
+ }
856
+
857
+ impl Debug for ValidationOp {
858
+ fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
859
+ use self :: ValidationOp :: * ;
860
+ match * self {
861
+ Acquire => write ! ( fmt, "Acquire" ) ,
862
+ Release => write ! ( fmt, "Release" ) ,
863
+ // (reuse lifetime rendering policy from ppaux.)
864
+ Suspend ( ref ce) => write ! ( fmt, "Suspend({})" , ty:: ReScope ( * ce) ) ,
865
+ }
866
+ }
867
+ }
868
+
869
+ // This is generic so that it can be reused by miri
870
+ #[ derive( Clone , RustcEncodable , RustcDecodable ) ]
871
+ pub struct ValidationOperand < ' tcx , T > {
872
+ pub lval : T ,
873
+ pub ty : Ty < ' tcx > ,
874
+ pub re : Option < CodeExtent > ,
875
+ pub mutbl : hir:: Mutability ,
876
+ }
877
+
878
+ impl < ' tcx , T : Debug > Debug for ValidationOperand < ' tcx , T > {
879
+ fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
880
+ write ! ( fmt, "{:?}: {:?}" , self . lval, self . ty) ?;
881
+ if let Some ( ce) = self . re {
882
+ // (reuse lifetime rendering policy from ppaux.)
883
+ write ! ( fmt, "/{}" , ty:: ReScope ( ce) ) ?;
884
+ }
885
+ if let hir:: MutImmutable = self . mutbl {
886
+ write ! ( fmt, " (imm)" ) ?;
887
+ }
888
+ Ok ( ( ) )
889
+ }
890
+ }
891
+
835
892
impl < ' tcx > Debug for Statement < ' tcx > {
836
893
fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
837
894
use self :: StatementKind :: * ;
838
895
match self . kind {
839
896
Assign ( ref lv, ref rv) => write ! ( fmt, "{:?} = {:?}" , lv, rv) ,
840
897
// (reuse lifetime rendering policy from ppaux.)
841
898
EndRegion ( ref ce) => write ! ( fmt, "EndRegion({})" , ty:: ReScope ( * ce) ) ,
899
+ Validate ( ref op, ref lvalues) => write ! ( fmt, "Validate({:?}, {:?})" , op, lvalues) ,
842
900
StorageLive ( ref lv) => write ! ( fmt, "StorageLive({:?})" , lv) ,
843
901
StorageDead ( ref lv) => write ! ( fmt, "StorageDead({:?})" , lv) ,
844
902
SetDiscriminant { lvalue : ref lv, variant_index : index} => {
@@ -1481,6 +1539,21 @@ impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
1481
1539
}
1482
1540
}
1483
1541
1542
+ impl < ' tcx > TypeFoldable < ' tcx > for ValidationOperand < ' tcx , Lvalue < ' tcx > > {
1543
+ fn super_fold_with < ' gcx : ' tcx , F : TypeFolder < ' gcx , ' tcx > > ( & self , folder : & mut F ) -> Self {
1544
+ ValidationOperand {
1545
+ lval : self . lval . fold_with ( folder) ,
1546
+ ty : self . ty . fold_with ( folder) ,
1547
+ re : self . re ,
1548
+ mutbl : self . mutbl ,
1549
+ }
1550
+ }
1551
+
1552
+ fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> bool {
1553
+ self . lval . visit_with ( visitor) || self . ty . visit_with ( visitor)
1554
+ }
1555
+ }
1556
+
1484
1557
impl < ' tcx > TypeFoldable < ' tcx > for Statement < ' tcx > {
1485
1558
fn super_fold_with < ' gcx : ' tcx , F : TypeFolder < ' gcx , ' tcx > > ( & self , folder : & mut F ) -> Self {
1486
1559
use mir:: StatementKind :: * ;
@@ -1505,6 +1578,10 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
1505
1578
// trait with a `fn fold_extent`.
1506
1579
EndRegion ( ref extent) => EndRegion ( extent. clone ( ) ) ,
1507
1580
1581
+ Validate ( ref op, ref lvals) =>
1582
+ Validate ( op. clone ( ) ,
1583
+ lvals. iter ( ) . map ( |operand| operand. fold_with ( folder) ) . collect ( ) ) ,
1584
+
1508
1585
Nop => Nop ,
1509
1586
} ;
1510
1587
Statement {
@@ -1530,6 +1607,9 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
1530
1607
// trait with a `fn visit_extent`.
1531
1608
EndRegion ( ref _extent) => false ,
1532
1609
1610
+ Validate ( ref _op, ref lvalues) =>
1611
+ lvalues. iter ( ) . any ( |ty_and_lvalue| ty_and_lvalue. visit_with ( visitor) ) ,
1612
+
1533
1613
Nop => false ,
1534
1614
}
1535
1615
}
0 commit comments