1
1
//! Propagates constants for early reporting of statically known
2
2
//! assertion failures
3
3
4
-
5
4
use 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
+ } ;
9
11
use rustc:: mir:: visit:: { Visitor , PlaceContext , MutatingUseContext , NonMutatingUseContext } ;
10
12
use 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 ;
13
15
use rustc:: ty:: subst:: InternalSubsts ;
14
16
use rustc_data_structures:: indexed_vec:: IndexVec ;
15
- use rustc:: ty:: ParamEnv ;
16
17
use rustc:: ty:: layout:: {
17
18
LayoutOf , TyLayout , LayoutError ,
18
19
HasTyCtxt , TargetDataLayout , HasDataLayout ,
@@ -62,21 +63,33 @@ impl MirPass for ConstProp {
62
63
let mut optimization_finder = ConstPropagator :: new ( mir, tcx, source) ;
63
64
optimization_finder. visit_mir ( mir) ;
64
65
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
+
65
76
trace ! ( "ConstProp done for {:?}" , source. def_id( ) ) ;
66
77
}
67
78
}
68
79
69
- type Const < ' tcx > = ( OpTy < ' tcx > , Span ) ;
80
+ type Const < ' tcx > = OpTy < ' tcx > ;
70
81
71
82
/// Finds optimization opportunities on the MIR.
72
83
struct ConstPropagator < ' a , ' mir , ' tcx : ' a +' mir > {
73
84
ecx : InterpretCx < ' a , ' mir , ' tcx , CompileTimeInterpreter < ' a , ' mir , ' tcx > > ,
74
- mir : & ' mir Mir < ' tcx > ,
75
85
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
76
86
source : MirSource < ' tcx > ,
77
87
places : IndexVec < Local , Option < Const < ' tcx > > > ,
78
88
can_const_prop : IndexVec < Local , bool > ,
79
89
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 > > ,
80
93
}
81
94
82
95
impl < ' a , ' b , ' tcx > LayoutOf for ConstPropagator < ' a , ' b , ' tcx > {
@@ -104,20 +117,33 @@ impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'a, 'b, 'tcx> {
104
117
105
118
impl < ' a , ' mir , ' tcx > ConstPropagator < ' a , ' mir , ' tcx > {
106
119
fn new (
107
- mir : & ' mir Mir < ' tcx > ,
120
+ mir : & mut Mir < ' tcx > ,
108
121
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
109
122
source : MirSource < ' tcx > ,
110
123
) -> ConstPropagator < ' a , ' mir , ' tcx > {
111
124
let param_env = tcx. param_env ( source. def_id ( ) ) ;
112
125
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
+
113
136
ConstPropagator {
114
137
ecx,
115
- mir,
116
138
tcx,
117
139
source,
118
140
param_env,
119
- can_const_prop : CanConstProp :: check ( mir ) ,
141
+ can_const_prop,
120
142
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,
121
147
}
122
148
}
123
149
@@ -130,7 +156,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
130
156
F : FnOnce ( & mut Self ) -> EvalResult < ' tcx , T > ,
131
157
{
132
158
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 {
134
160
ClearCrossCrate :: Set ( ref ivs) => {
135
161
//FIXME(#51314): remove this check
136
162
if source_info. scope . index ( ) >= ivs. len ( ) {
@@ -252,12 +278,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
252
278
fn eval_constant (
253
279
& mut self ,
254
280
c : & Constant < ' tcx > ,
255
- source_info : SourceInfo ,
256
281
) -> Option < Const < ' tcx > > {
257
- self . ecx . tcx . span = source_info . span ;
282
+ self . ecx . tcx . span = c . span ;
258
283
match self . ecx . eval_const_to_op ( * c. literal , None ) {
259
284
Ok ( op) => {
260
- Some ( ( op , c . span ) )
285
+ Some ( op )
261
286
} ,
262
287
Err ( error) => {
263
288
let err = error_to_const_error ( & self . ecx , error) ;
@@ -273,11 +298,11 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
273
298
Place :: Projection ( ref proj) => match proj. elem {
274
299
ProjectionElem :: Field ( field, _) => {
275
300
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) ?;
277
302
let res = self . use_ecx ( source_info, |this| {
278
303
this. ecx . operand_field ( base, field. index ( ) as u64 )
279
304
} ) ?;
280
- Some ( ( res, span ) )
305
+ Some ( res)
281
306
} ,
282
307
// We could get more projections by using e.g., `operand_projection`,
283
308
// 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> {
301
326
// cannot use `const_eval` here, because that would require having the MIR
302
327
// for the current function available, but we're producing said MIR right now
303
328
let res = self . use_ecx ( source_info, |this| {
304
- let mir = & this. mir . promoted [ promoted] ;
329
+ let mir = & this. promoted [ promoted] ;
305
330
eval_promoted ( this. tcx , cid, mir, this. param_env )
306
331
} ) ?;
307
332
trace ! ( "evaluated promoted {:?} to {:?}" , promoted, res) ;
308
- Some ( ( res. into ( ) , source_info . span ) )
333
+ Some ( res. into ( ) )
309
334
} ,
310
335
_ => None ,
311
336
}
312
337
}
313
338
314
339
fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < Const < ' tcx > > {
315
340
match * op {
316
- Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
341
+ Operand :: Constant ( ref c) => self . eval_constant ( c) ,
317
342
| Operand :: Move ( ref place)
318
343
| Operand :: Copy ( ref place) => self . eval_place ( place, source_info) ,
319
344
}
@@ -337,18 +362,18 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
337
362
Rvalue :: Discriminant ( ..) => None ,
338
363
339
364
Rvalue :: Cast ( kind, ref operand, _) => {
340
- let ( op , span ) = self . eval_operand ( operand, source_info) ?;
365
+ let op = self . eval_operand ( operand, source_info) ?;
341
366
self . use_ecx ( source_info, |this| {
342
367
let dest = this. ecx . allocate ( place_layout, MemoryKind :: Stack ) ;
343
368
this. ecx . cast ( op, kind, dest. into ( ) ) ?;
344
- Ok ( ( dest. into ( ) , span ) )
369
+ Ok ( dest. into ( ) )
345
370
} )
346
371
}
347
372
348
373
// FIXME(oli-obk): evaluate static/constant slice lengths
349
374
Rvalue :: Len ( _) => None ,
350
375
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 (
352
377
ImmTy {
353
378
imm : Immediate :: Scalar (
354
379
Scalar :: Bits {
@@ -357,9 +382,8 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
357
382
} . into ( )
358
383
) ,
359
384
layout : self . tcx . layout_of ( self . param_env . and ( self . tcx . types . usize ) ) . ok ( ) ?,
360
- } . into ( ) ,
361
- span,
362
- ) ) )
385
+ } . into ( )
386
+ ) )
363
387
}
364
388
Rvalue :: UnaryOp ( op, ref arg) => {
365
389
let def_id = if self . tcx . is_closure ( self . source . def_id ( ) ) {
@@ -373,7 +397,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
373
397
return None ;
374
398
}
375
399
376
- let ( arg, _ ) = self . eval_operand ( arg, source_info) ?;
400
+ let arg = self . eval_operand ( arg, source_info) ?;
377
401
let val = self . use_ecx ( source_info, |this| {
378
402
let prim = this. ecx . read_immediate ( arg) ?;
379
403
match op {
@@ -395,7 +419,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
395
419
imm : Immediate :: Scalar ( val. into ( ) ) ,
396
420
layout : place_layout,
397
421
} ;
398
- Some ( ( res. into ( ) , span ) )
422
+ Some ( res. into ( ) )
399
423
}
400
424
Rvalue :: CheckedBinaryOp ( op, ref left, ref right) |
401
425
Rvalue :: BinaryOp ( op, ref left, ref right) => {
@@ -413,20 +437,20 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
413
437
}
414
438
415
439
let r = self . use_ecx ( source_info, |this| {
416
- this. ecx . read_immediate ( right. 0 )
440
+ this. ecx . read_immediate ( right)
417
441
} ) ?;
418
442
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 ) ;
420
444
let left_bits = self
421
445
. tcx
422
446
. layout_of ( self . param_env . and ( left_ty) )
423
447
. unwrap ( )
424
448
. size
425
449
. bits ( ) ;
426
- let right_size = right. 0 . layout . size ;
450
+ let right_size = right. layout . size ;
427
451
let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
428
452
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 {
430
454
ClearCrossCrate :: Set ( ref data) => data,
431
455
ClearCrossCrate :: Clear => return None ,
432
456
} ;
@@ -446,7 +470,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
446
470
}
447
471
let left = self . eval_operand ( left, source_info) ?;
448
472
let l = self . use_ecx ( source_info, |this| {
449
- this. ecx . read_immediate ( left. 0 )
473
+ this. ecx . read_immediate ( left)
450
474
} ) ?;
451
475
trace ! ( "const evaluating {:?} for {:?} and {:?}" , op, left, right) ;
452
476
let ( val, overflow) = self . use_ecx ( source_info, |this| {
@@ -469,7 +493,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
469
493
imm : val,
470
494
layout : place_layout,
471
495
} ;
472
- Some ( ( res. into ( ) , span ) )
496
+ Some ( res. into ( ) )
473
497
} ,
474
498
}
475
499
}
@@ -544,8 +568,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
544
568
) {
545
569
trace ! ( "visit_constant: {:?}" , constant) ;
546
570
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) ;
549
572
}
550
573
551
574
fn visit_statement (
@@ -556,7 +579,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
556
579
trace ! ( "visit_statement: {:?}" , statement) ;
557
580
if let StatementKind :: Assign ( ref place, ref rval) = statement. kind {
558
581
let place_ty: Ty < ' tcx > = place
559
- . ty ( & self . mir . local_decls , self . tcx )
582
+ . ty ( & self . local_decls , self . tcx )
560
583
. ty ;
561
584
if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
562
585
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> {
574
597
self . super_statement ( statement, location) ;
575
598
}
576
599
577
- fn visit_terminator_kind (
600
+ fn visit_terminator (
578
601
& mut self ,
579
- kind : & TerminatorKind < ' tcx > ,
602
+ terminator : & Terminator < ' tcx > ,
580
603
location : Location ,
581
604
) {
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) {
586
609
trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
587
610
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 ( ) {
589
612
// poison all places this operand references so that further code
590
613
// doesn't use the invalid value
591
614
match cond {
@@ -600,12 +623,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
600
623
} ,
601
624
Operand :: Constant ( _) => { }
602
625
}
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 ;
609
627
let hir_id = self
610
628
. tcx
611
629
. hir ( )
@@ -621,7 +639,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
621
639
let len = self
622
640
. eval_operand ( len, source_info)
623
641
. expect ( "len must be const" ) ;
624
- let len = match self . ecx . read_scalar ( len. 0 ) {
642
+ let len = match self . ecx . read_scalar ( len) {
625
643
Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
626
644
bits, ..
627
645
} ) ) => bits,
@@ -630,7 +648,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
630
648
let index = self
631
649
. eval_operand ( index, source_info)
632
650
. expect ( "index must be const" ) ;
633
- let index = match self . ecx . read_scalar ( index. 0 ) {
651
+ let index = match self . ecx . read_scalar ( index) {
634
652
Ok ( ScalarMaybeUndef :: Scalar ( Scalar :: Bits {
635
653
bits, ..
636
654
} ) ) => bits,
0 commit comments