@@ -25,7 +25,7 @@ use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
2525use ty:: fold:: { TypeFoldable , TypeFolder , TypeVisitor } ;
2626use util:: ppaux;
2727use rustc_back:: slice;
28- use hir:: InlineAsm ;
28+ use hir:: { self , InlineAsm } ;
2929use std:: ascii;
3030use std:: borrow:: { Cow } ;
3131use std:: cell:: Ref ;
@@ -818,12 +818,18 @@ pub enum StatementKind<'tcx> {
818818 /// End the current live range for the storage of the local.
819819 StorageDead ( Lvalue < ' tcx > ) ,
820820
821+ /// Execute a piece of inline Assembly.
821822 InlineAsm {
822823 asm : Box < InlineAsm > ,
823824 outputs : Vec < Lvalue < ' tcx > > ,
824825 inputs : Vec < Operand < ' tcx > >
825826 } ,
826827
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+
827833 /// Mark one terminating point of an extent (i.e. static region).
828834 /// (The starting point(s) arise implicitly from borrows.)
829835 EndRegion ( CodeExtent ) ,
@@ -832,13 +838,65 @@ pub enum StatementKind<'tcx> {
832838 Nop ,
833839}
834840
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+
835892impl < ' tcx > Debug for Statement < ' tcx > {
836893 fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
837894 use self :: StatementKind :: * ;
838895 match self . kind {
839896 Assign ( ref lv, ref rv) => write ! ( fmt, "{:?} = {:?}" , lv, rv) ,
840897 // (reuse lifetime rendering policy from ppaux.)
841898 EndRegion ( ref ce) => write ! ( fmt, "EndRegion({})" , ty:: ReScope ( * ce) ) ,
899+ Validate ( ref op, ref lvalues) => write ! ( fmt, "Validate({:?}, {:?})" , op, lvalues) ,
842900 StorageLive ( ref lv) => write ! ( fmt, "StorageLive({:?})" , lv) ,
843901 StorageDead ( ref lv) => write ! ( fmt, "StorageDead({:?})" , lv) ,
844902 SetDiscriminant { lvalue : ref lv, variant_index : index} => {
@@ -1481,6 +1539,21 @@ impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
14811539 }
14821540}
14831541
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+
14841557impl < ' tcx > TypeFoldable < ' tcx > for Statement < ' tcx > {
14851558 fn super_fold_with < ' gcx : ' tcx , F : TypeFolder < ' gcx , ' tcx > > ( & self , folder : & mut F ) -> Self {
14861559 use mir:: StatementKind :: * ;
@@ -1505,6 +1578,10 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
15051578 // trait with a `fn fold_extent`.
15061579 EndRegion ( ref extent) => EndRegion ( extent. clone ( ) ) ,
15071580
1581+ Validate ( ref op, ref lvals) =>
1582+ Validate ( op. clone ( ) ,
1583+ lvals. iter ( ) . map ( |operand| operand. fold_with ( folder) ) . collect ( ) ) ,
1584+
15081585 Nop => Nop ,
15091586 } ;
15101587 Statement {
@@ -1530,6 +1607,9 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
15301607 // trait with a `fn visit_extent`.
15311608 EndRegion ( ref _extent) => false ,
15321609
1610+ Validate ( ref _op, ref lvalues) =>
1611+ lvalues. iter ( ) . any ( |ty_and_lvalue| ty_and_lvalue. visit_with ( visitor) ) ,
1612+
15331613 Nop => false ,
15341614 }
15351615 }
0 commit comments