1
1
//! Propagates constants for early reporting of statically known
2
2
//! assertion failures
3
3
4
+ use std:: cell:: Cell ;
5
+
4
6
use rustc:: hir:: def:: DefKind ;
5
7
use rustc:: mir:: {
6
8
AggregateKind , Constant , Location , Place , PlaceBase , Body , Operand , Rvalue ,
@@ -21,7 +23,8 @@ use rustc::ty::layout::{
21
23
} ;
22
24
23
25
use crate :: interpret:: {
24
- self , InterpretCx , ScalarMaybeUndef , Immediate , OpTy , ImmTy , MemoryKind ,
26
+ self , InterpretCx , ScalarMaybeUndef , Immediate , OpTy ,
27
+ ImmTy , MemoryKind , StackPopCleanup , LocalValue , LocalState ,
25
28
} ;
26
29
use crate :: const_eval:: {
27
30
CompileTimeInterpreter , error_to_const_error, eval_promoted, mk_eval_cx,
@@ -56,21 +59,54 @@ impl MirPass for ConstProp {
56
59
57
60
trace ! ( "ConstProp starting for {:?}" , source. def_id( ) ) ;
58
61
62
+ // Steal some data we need from `body`.
63
+ let source_scope_local_data = std:: mem:: replace (
64
+ & mut body. source_scope_local_data ,
65
+ ClearCrossCrate :: Clear
66
+ ) ;
67
+ let promoted = std:: mem:: replace (
68
+ & mut body. promoted ,
69
+ IndexVec :: new ( )
70
+ ) ;
71
+
72
+ let dummy_body =
73
+ & Body :: new (
74
+ body. basic_blocks ( ) . clone ( ) ,
75
+ Default :: default ( ) ,
76
+ ClearCrossCrate :: Clear ,
77
+ Default :: default ( ) ,
78
+ None ,
79
+ body. local_decls . clone ( ) ,
80
+ Default :: default ( ) ,
81
+ body. arg_count ,
82
+ Default :: default ( ) ,
83
+ tcx. def_span ( source. def_id ( ) ) ,
84
+ Default :: default ( ) ,
85
+ ) ;
86
+
59
87
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
60
88
// constants, instead of just checking for const-folding succeeding.
61
89
// That would require an uniform one-def no-mutation analysis
62
90
// and RPO (or recursing when needing the value of a local).
63
- let mut optimization_finder = ConstPropagator :: new ( body, tcx, source) ;
91
+ let mut optimization_finder = ConstPropagator :: new (
92
+ body,
93
+ dummy_body,
94
+ source_scope_local_data,
95
+ promoted,
96
+ tcx,
97
+ source
98
+ ) ;
64
99
optimization_finder. visit_body ( body) ;
65
100
66
101
// put back the data we stole from `mir`
102
+ let ( source_scope_local_data, promoted) = optimization_finder. release_stolen_data ( ) ;
67
103
std:: mem:: replace (
68
104
& mut body. source_scope_local_data ,
69
- optimization_finder . source_scope_local_data
105
+ source_scope_local_data
70
106
) ;
71
107
std:: mem:: replace (
72
108
& mut body. promoted ,
73
- optimization_finder . promoted
109
+ promoted
74
110
) ;
75
111
76
112
trace ! ( "ConstProp done for {:?}" , source. def_id( ) ) ;
@@ -84,7 +120,6 @@ struct ConstPropagator<'mir, 'tcx> {
84
120
ecx : InterpretCx < ' mir , ' tcx , CompileTimeInterpreter < ' mir , ' tcx > > ,
85
121
tcx : TyCtxt < ' tcx > ,
86
122
source : MirSource < ' tcx > ,
87
- places : IndexVec < Local , Option < Const < ' tcx > > > ,
88
123
can_const_prop : IndexVec < Local , bool > ,
89
124
param_env : ParamEnv < ' tcx > ,
90
125
source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
@@ -117,36 +152,87 @@ impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
117
152
118
153
impl < ' mir , ' tcx > ConstPropagator < ' mir , ' tcx > {
119
154
fn new (
120
- body : & mut Body < ' tcx > ,
155
+ body : & Body < ' tcx > ,
156
+ dummy_body : & ' mir Body < ' tcx > ,
157
+ source_scope_local_data : ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
158
+ promoted : IndexVec < Promoted , Body < ' tcx > > ,
121
159
tcx : TyCtxt < ' tcx > ,
122
160
source : MirSource < ' tcx > ,
123
161
) -> ConstPropagator < ' mir , ' tcx > {
124
- let param_env = tcx. param_env ( source. def_id ( ) ) ;
125
- let ecx = mk_eval_cx ( tcx, tcx. def_span ( source. def_id ( ) ) , param_env) ;
162
+ let def_id = source. def_id ( ) ;
163
+ let param_env = tcx. param_env ( def_id) ;
164
+ let span = tcx. def_span ( def_id) ;
165
+ let mut ecx = mk_eval_cx ( tcx, span, param_env) ;
126
166
let can_const_prop = CanConstProp :: check ( body) ;
127
- let source_scope_local_data = std:: mem:: replace (
128
- & mut body. source_scope_local_data ,
129
- ClearCrossCrate :: Clear
130
- ) ;
131
- let promoted = std:: mem:: replace (
132
- & mut body. promoted ,
133
- IndexVec :: new ( )
134
- ) ;
167
+
168
+ ecx. push_stack_frame (
169
+ Instance :: new ( def_id, & InternalSubsts :: identity_for_item ( tcx, def_id) ) ,
170
+ span,
171
+ dummy_body,
172
+ None ,
173
+ StackPopCleanup :: None {
174
+ cleanup : false ,
175
+ } ,
176
+ ) . expect ( "failed to push initial stack frame" ) ;
135
177
136
178
ConstPropagator {
137
179
ecx,
138
180
tcx,
139
181
source,
140
182
param_env,
141
183
can_const_prop,
142
- places : IndexVec :: from_elem ( None , & body. local_decls ) ,
143
184
source_scope_local_data,
144
185
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
145
186
local_decls : body. local_decls . clone ( ) ,
146
187
promoted,
147
188
}
148
189
}
149
190
191
+ fn release_stolen_data (
192
+ self ,
193
+ ) -> (
194
+ ClearCrossCrate < IndexVec < SourceScope , SourceScopeLocalData > > ,
195
+ IndexVec < Promoted , Body < ' tcx > > ,
196
+ ) {
197
+ ( self . source_scope_local_data , self . promoted )
198
+ }
199
+
200
+ fn get_const ( & self , local : Local ) -> Option < Const < ' tcx > > {
201
+ let l = & self . ecx . frame ( ) . locals [ local] ;
202
+
203
+ // If the local is `Unitialized` or `Dead` then we haven't propagated a value into it.
204
+ //
205
+ // `InterpretCx::access_local()` mostly takes care of this for us however, for ZSTs,
206
+ // it will synthesize a value for us. In doing so, that will cause the
207
+ // `get_const(l).is_empty()` assert right before we call `set_const()` in `visit_statement`
208
+ // to fail.
209
+ if let LocalValue :: Uninitialized | LocalValue :: Dead = l. value {
210
+ return None ;
211
+ }
212
+
213
+ self . ecx . access_local ( self . ecx . frame ( ) , local, None ) . ok ( )
214
+ }
215
+
216
+ fn set_const ( & mut self , local : Local , c : Const < ' tcx > ) {
217
+ let frame = self . ecx . frame_mut ( ) ;
218
+
219
+ if let Some ( layout) = frame. locals [ local] . layout . get ( ) {
220
+ debug_assert_eq ! ( c. layout, layout) ;
221
+ }
222
+
223
+ frame. locals [ local] = LocalState {
224
+ value : LocalValue :: Live ( * c) ,
225
+ layout : Cell :: new ( Some ( c. layout ) ) ,
226
+ } ;
227
+ }
228
+
229
+ fn remove_const ( & mut self , local : Local ) {
230
+ self . ecx . frame_mut ( ) . locals [ local] = LocalState {
231
+ value : LocalValue :: Uninitialized ,
232
+ layout : Cell :: new ( None ) ,
233
+ } ;
234
+ }
235
+
150
236
fn use_ecx < F , T > (
151
237
& mut self ,
152
238
source_info : SourceInfo ,
@@ -296,7 +382,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
296
382
trace ! ( "eval_place(place={:?})" , place) ;
297
383
place. iterate ( |place_base, place_projection| {
298
384
let mut eval = match place_base {
299
- PlaceBase :: Local ( loc) => self . places [ * loc] . clone ( ) ?,
385
+ PlaceBase :: Local ( loc) => self . get_const ( * loc) . clone ( ) ?,
300
386
PlaceBase :: Static ( box Static { kind : StaticKind :: Promoted ( promoted) , ..} ) => {
301
387
let generics = self . tcx . generics_of ( self . source . def_id ( ) ) ;
302
388
if generics. requires_monomorphization ( self . tcx ) {
@@ -699,8 +785,8 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
699
785
trace ! ( "checking whether {:?} can be stored to {:?}" , value, local) ;
700
786
if self . can_const_prop [ local] {
701
787
trace ! ( "storing {:?} to {:?}" , value, local) ;
702
- assert ! ( self . places [ local] . is_none( ) ) ;
703
- self . places [ local] = Some ( value) ;
788
+ assert ! ( self . get_const ( local) . is_none( ) ) ;
789
+ self . set_const ( local, value) ;
704
790
705
791
if self . should_const_prop ( ) {
706
792
self . replace_with_const (
@@ -740,7 +826,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
740
826
place = & proj. base ;
741
827
}
742
828
if let Place :: Base ( PlaceBase :: Local ( local) ) = * place {
743
- self . places [ local] = None ;
829
+ self . remove_const ( local) ;
744
830
}
745
831
} ,
746
832
Operand :: Constant ( _) => { }
0 commit comments