11//! Propagates constants for early reporting of statically known
22//! assertion failures
33
4-
54use rustc:: hir:: def:: Def ;
6- use rustc:: mir:: { Constant , Location , Place , PlaceBase , Mir , Operand , Rvalue , Local } ;
7- use rustc:: mir:: { NullOp , UnOp , StatementKind , Statement , LocalKind , Static , StaticKind } ;
8- use rustc:: mir:: { TerminatorKind , ClearCrossCrate , SourceInfo , BinOp , ProjectionElem } ;
5+ use rustc:: mir:: {
6+ Constant , Location , Place , PlaceBase , Mir , Operand , Rvalue , Local ,
7+ NullOp , UnOp , StatementKind , Statement , LocalKind , Static , StaticKind ,
8+ TerminatorKind , Terminator , ClearCrossCrate , SourceInfo , BinOp , ProjectionElem ,
9+ SourceScope , SourceScopeLocalData , LocalDecl , Promoted ,
10+ } ;
911use rustc:: mir:: visit:: { Visitor , PlaceContext , MutatingUseContext , NonMutatingUseContext } ;
1012use rustc:: mir:: interpret:: { InterpError , Scalar , GlobalId , EvalResult } ;
11- use rustc:: ty:: { self , Instance , Ty , TyCtxt } ;
12- use syntax:: source_map:: { Span , DUMMY_SP } ;
13+ use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
14+ use syntax:: source_map:: DUMMY_SP ;
1315use rustc:: ty:: subst:: InternalSubsts ;
1416use rustc_data_structures:: indexed_vec:: IndexVec ;
15- use rustc:: ty:: ParamEnv ;
1617use rustc:: ty:: layout:: {
1718 LayoutOf , TyLayout , LayoutError ,
1819 HasTyCtxt , TargetDataLayout , HasDataLayout ,
@@ -62,21 +63,33 @@ impl MirPass for ConstProp {
6263 let mut optimization_finder = ConstPropagator :: new ( mir, tcx, source) ;
6364 optimization_finder. visit_mir ( mir) ;
6465
66+ // put back the data we stole from `mir`
67+ std:: mem:: replace (
68+ & mut mir. source_scope_local_data ,
69+ optimization_finder. source_scope_local_data
70+ ) ;
71+ std:: mem:: replace (
72+ & mut mir. promoted ,
73+ optimization_finder. promoted
74+ ) ;
75+
6576 trace ! ( "ConstProp done for {:?}" , source. def_id( ) ) ;
6677 }
6778}
6879
69- type Const < ' tcx > = ( OpTy < ' tcx > , Span ) ;
80+ type Const < ' tcx > = OpTy < ' tcx > ;
7081
7182/// Finds optimization opportunities on the MIR.
7283struct ConstPropagator < ' a , ' mir , ' tcx : ' a +' mir > {
7384 ecx : InterpretCx < ' a , ' mir , ' tcx , CompileTimeInterpreter < ' a , ' mir , ' tcx > > ,
74- mir : & ' mir Mir < ' tcx > ,
7585 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
7686 source : MirSource < ' tcx > ,
7787 places : IndexVec < Local , Option < Const < ' tcx > > > ,
7888 can_const_prop : IndexVec < Local , bool > ,
7989 param_env : ParamEnv < ' tcx > ,
90+ source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
91+ local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
92+ promoted : IndexVec < Promoted , Mir < ' tcx > > ,
8093}
8194
8295impl < ' a , ' b , ' tcx > LayoutOf for ConstPropagator < ' a , ' b , ' tcx > {
@@ -104,20 +117,33 @@ impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'a, 'b, 'tcx> {
104117
105118impl < ' a , ' mir , ' tcx > ConstPropagator < ' a , ' mir , ' tcx > {
106119 fn new (
107- mir : & ' mir Mir < ' tcx > ,
120+ mir : & mut Mir < ' tcx > ,
108121 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
109122 source : MirSource < ' tcx > ,
110123 ) -> ConstPropagator < ' a , ' mir , ' tcx > {
111124 let param_env = tcx. param_env ( source. def_id ( ) ) ;
112125 let ecx = mk_eval_cx ( tcx, tcx. def_span ( source. def_id ( ) ) , param_env) ;
126+ let can_const_prop = CanConstProp :: check ( mir) ;
127+ let source_scope_local_data = std:: mem:: replace (
128+ & mut mir. source_scope_local_data ,
129+ ClearCrossCrate :: Clear
130+ ) ;
131+ let promoted = std:: mem:: replace (
132+ & mut mir. promoted ,
133+ IndexVec :: new ( )
134+ ) ;
135+
113136 ConstPropagator {
114137 ecx,
115- mir,
116138 tcx,
117139 source,
118140 param_env,
119- can_const_prop : CanConstProp :: check ( mir ) ,
141+ can_const_prop,
120142 places : IndexVec :: from_elem ( None , & mir. local_decls ) ,
143+ source_scope_local_data,
144+ //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_mir()` needs it
145+ local_decls : mir. local_decls . clone ( ) ,
146+ promoted,
121147 }
122148 }
123149
@@ -130,7 +156,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
130156 F : FnOnce ( & mut Self ) -> EvalResult < ' tcx , T > ,
131157 {
132158 self . ecx . tcx . span = source_info. span ;
133- let lint_root = match self . mir . source_scope_local_data {
159+ let lint_root = match self . source_scope_local_data {
134160 ClearCrossCrate :: Set ( ref ivs) => {
135161 //FIXME(#51314): remove this check
136162 if source_info. scope . index ( ) >= ivs. len ( ) {
@@ -252,12 +278,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
252278 fn eval_constant (
253279 & mut self ,
254280 c : & Constant < ' tcx > ,
255- source_info : SourceInfo ,
256281 ) -> Option < Const < ' tcx > > {
257- self . ecx . tcx . span = source_info . span ;
282+ self . ecx . tcx . span = c . span ;
258283 match self . ecx . eval_const_to_op ( * c. literal , None ) {
259284 Ok ( op) => {
260- Some ( ( op , c . span ) )
285+ Some ( op )
261286 } ,
262287 Err ( error) => {
263288 let err = error_to_const_error ( & self . ecx , error) ;
@@ -273,11 +298,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
273298 Place :: Projection ( ref proj) => match proj. elem {
274299 ProjectionElem :: Field ( field, _) => {
275300 trace ! ( "field proj on {:?}" , proj. base) ;
276- let ( base, span ) = self . eval_place ( & proj. base , source_info) ?;
301+ let base = self . eval_place ( & proj. base , source_info) ?;
277302 let res = self . use_ecx ( source_info, |this| {
278303 this. ecx . operand_field ( base, field. index ( ) as u64 )
279304 } ) ?;
280- Some ( ( res, span ) )
305+ Some ( res)
281306 } ,
282307 // We could get more projections by using e.g., `operand_projection`,
283308 // but we do not even have the stack frame set up properly so
@@ -301,19 +326,19 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
301326 // cannot use `const_eval` here, because that would require having the MIR
302327 // for the current function available, but we're producing said MIR right now
303328 let res = self . use_ecx ( source_info, |this| {
304- let mir = & this. mir . promoted [ promoted] ;
329+ let mir = & this. promoted [ promoted] ;
305330 eval_promoted ( this. tcx , cid, mir, this. param_env )
306331 } ) ?;
307332 trace ! ( "evaluated promoted {:?} to {:?}" , promoted, res) ;
308- Some ( ( res. into ( ) , source_info . span ) )
333+ Some ( res. into ( ) )
309334 } ,
310335 _ => None ,
311336 }
312337 }
313338
314339 fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < Const < ' tcx > > {
315340 match * op {
316- Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
341+ Operand :: Constant ( ref c) => self . eval_constant ( c) ,
317342 | Operand :: Move ( ref place)
318343 | Operand :: Copy ( ref place) => self . eval_place ( place, source_info) ,
319344 }
@@ -337,18 +362,18 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
337362 Rvalue :: Discriminant ( ..) => None ,
338363
339364 Rvalue :: Cast ( kind, ref operand, _) => {
340- let ( op , span ) = self . eval_operand ( operand, source_info) ?;
365+ let op = self . eval_operand ( operand, source_info) ?;
341366 self . use_ecx ( source_info, |this| {
342367 let dest = this. ecx . allocate ( place_layout, MemoryKind :: Stack ) ;
343368 this. ecx . cast ( op, kind, dest. into ( ) ) ?;
344- Ok ( ( dest. into ( ) , span ) )
369+ Ok ( dest. into ( ) )
345370 } )
346371 }
347372
348373 // FIXME(oli-obk): evaluate static/constant slice lengths
349374 Rvalue :: Len ( _) => None ,
350375 Rvalue :: NullaryOp ( NullOp :: SizeOf , ty) => {
351- type_size_of ( self . tcx , self . param_env , ty) . and_then ( |n| Some ( (
376+ type_size_of ( self . tcx , self . param_env , ty) . and_then ( |n| Some (
352377 ImmTy {
353378 imm : Immediate :: Scalar (
354379 Scalar :: Bits {
@@ -357,9 +382,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
357382 } . into ( )
358383 ) ,
359384 layout : self . tcx . layout_of ( self . param_env . and ( self . tcx . types . usize ) ) . ok ( ) ?,
360- } . into ( ) ,
361- span,
362- ) ) )
385+ } . into ( )
386+ ) )
363387 }
364388 Rvalue :: UnaryOp ( op, ref arg) => {
365389 let def_id = if self . tcx . is_closure ( self . source . def_id ( ) ) {
@@ -373,7 +397,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
373397 return None ;
374398 }
375399
376- let ( arg, _ ) = self . eval_operand ( arg, source_info) ?;
400+ let arg = self . eval_operand ( arg, source_info) ?;
377401 let val = self . use_ecx ( source_info, |this| {
378402 let prim = this. ecx . read_immediate ( arg) ?;
379403 match op {
@@ -395,7 +419,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
395419 imm : Immediate :: Scalar ( val. into ( ) ) ,
396420 layout : place_layout,
397421 } ;
398- Some ( ( res. into ( ) , span ) )
422+ Some ( res. into ( ) )
399423 }
400424 Rvalue :: CheckedBinaryOp ( op, ref left, ref right) |
401425 Rvalue :: BinaryOp ( op, ref left, ref right) => {
@@ -413,20 +437,20 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
413437 }
414438
415439 let r = self . use_ecx ( source_info, |this| {
416- this. ecx . read_immediate ( right. 0 )
440+ this. ecx . read_immediate ( right)
417441 } ) ?;
418442 if op == BinOp :: Shr || op == BinOp :: Shl {
419- let left_ty = left. ty ( self . mir , self . tcx ) ;
443+ let left_ty = left. ty ( & self . local_decls , self . tcx ) ;
420444 let left_bits = self
421445 . tcx
422446 . layout_of ( self . param_env . and ( left_ty) )
423447 . unwrap ( )
424448 . size
425449 . bits ( ) ;
426- let right_size = right. 0 . layout . size ;
450+ let right_size = right. layout . size ;
427451 let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
428452 if r_bits. ok ( ) . map_or ( false , |b| b >= left_bits as u128 ) {
429- let source_scope_local_data = match self . mir . source_scope_local_data {
453+ let source_scope_local_data = match self . source_scope_local_data {
430454 ClearCrossCrate :: Set ( ref data) => data,
431455 ClearCrossCrate :: Clear => return None ,
432456 } ;
@@ -446,7 +470,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
446470 }
447471 let left = self . eval_operand ( left, source_info) ?;
448472 let l = self . use_ecx ( source_info, |this| {
449- this. ecx . read_immediate ( left. 0 )
473+ this. ecx . read_immediate ( left)
450474 } ) ?;
451475 trace ! ( "const evaluating {:?} for {:?} and {:?}" , op, left, right) ;
452476 let ( val, overflow) = self . use_ecx ( source_info, |this| {
@@ -469,7 +493,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
469493 imm : val,
470494 layout : place_layout,
471495 } ;
472- Some ( ( res. into ( ) , span ) )
496+ Some ( res. into ( ) )
473497 } ,
474498 }
475499 }
@@ -544,8 +568,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
544568 ) {
545569 trace ! ( "visit_constant: {:?}" , constant) ;
546570 self . super_constant ( constant, location) ;
547- let source_info = * self . mir . source_info ( location) ;
548- self . eval_constant ( constant, source_info) ;
571+ self . eval_constant ( constant) ;
549572 }
550573
551574 fn visit_statement (
@@ -556,7 +579,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
556579 trace ! ( "visit_statement: {:?}" , statement) ;
557580 if let StatementKind :: Assign ( ref place, ref rval) = statement. kind {
558581 let place_ty: Ty < ' tcx > = place
559- . ty ( & self . mir . local_decls , self . tcx )
582+ . ty ( & self . local_decls , self . tcx )
560583 . ty ;
561584 if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
562585 if let Some ( value) = self . const_prop ( rval, place_layout, statement. source_info ) {
@@ -574,18 +597,18 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
574597 self . super_statement ( statement, location) ;
575598 }
576599
577- fn visit_terminator_kind (
600+ fn visit_terminator (
578601 & mut self ,
579- kind : & TerminatorKind < ' tcx > ,
602+ terminator : & Terminator < ' tcx > ,
580603 location : Location ,
581604 ) {
582- self . super_terminator_kind ( kind , location) ;
583- let source_info = * self . mir . source_info ( location ) ;
584- if let TerminatorKind :: Assert { expected, msg, cond, .. } = kind {
585- if let Some ( value) = self . eval_operand ( cond, source_info) {
605+ self . super_terminator ( terminator , location) ;
606+ let source_info = terminator . source_info ; ;
607+ if let TerminatorKind :: Assert { expected, msg, cond, .. } = & terminator . kind {
608+ if let Some ( value) = self . eval_operand ( & cond, source_info) {
586609 trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
587610 let expected = ScalarMaybeUndef :: from ( Scalar :: from_bool ( * expected) ) ;
588- if expected != self . ecx . read_scalar ( value. 0 ) . unwrap ( ) {
611+ if expected != self . ecx . read_scalar ( value) . unwrap ( ) {
589612 // poison all places this operand references so that further code
590613 // doesn't use the invalid value
591614 match cond {
@@ -600,12 +623,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
600623 } ,
601624 Operand :: Constant ( _) => { }
602625 }
603- let span = self . mir [ location. block ]
604- . terminator
605- . as_ref ( )
606- . unwrap ( )
607- . source_info
608- . span ;
626+ let span = terminator. source_info . span ;
609627 let hir_id = self
610628 . tcx
611629 . hir ( )
@@ -621,7 +639,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
621639 let len = self
622640 . eval_operand ( len, source_info)
623641 . expect ( "len must be const" ) ;
624- let len = match self . ecx . read_scalar ( len. 0 ) {
642+ let len = match self . ecx . read_scalar ( len) {
625643 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
626644 bits, ..
627645 } ) ) => bits,
@@ -630,7 +648,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
630648 let index = self
631649 . eval_operand ( index, source_info)
632650 . expect ( "index must be const" ) ;
633- let index = match self . ecx . read_scalar ( index. 0 ) {
651+ let index = match self . ecx . read_scalar ( index) {
634652 Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
635653 bits, ..
636654 } ) ) => bits,
0 commit comments