@@ -60,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
60
60
61
61
let mut rpo = traversal:: reverse_postorder ( body) ;
62
62
let ccx = ConstCx :: new ( tcx, body) ;
63
- let ( temps, all_candidates) = collect_temps_and_candidates ( & ccx, & mut rpo) ;
63
+ let ( mut temps, all_candidates) = collect_temps_and_candidates ( & ccx, & mut rpo) ;
64
64
65
- let promotable_candidates = validate_candidates ( & ccx, & temps, & all_candidates) ;
65
+ let promotable_candidates = validate_candidates ( & ccx, & mut temps, & all_candidates) ;
66
66
67
67
let promoted = promote_candidates ( body, tcx, temps, promotable_candidates) ;
68
68
self . promoted_fragments . set ( promoted) ;
@@ -77,14 +77,21 @@ pub enum TempState {
77
77
/// One direct assignment and any number of direct uses.
78
78
/// A borrow of this temp is promotable if the assigned
79
79
/// value is qualified as constant.
80
- Defined { location : Location , uses : usize } ,
80
+ Defined { location : Location , uses : usize , valid : Valid } ,
81
81
/// Any other combination of assignments/uses.
82
82
Unpromotable ,
83
83
/// This temp was part of an rvalue which got extracted
84
84
/// during promotion and needs cleanup.
85
85
PromotedOut ,
86
86
}
87
87
88
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
89
+ pub enum Valid {
90
+ Unknown ,
91
+ InValid ,
92
+ Validated ,
93
+ }
94
+
88
95
impl TempState {
89
96
pub fn is_promotable ( & self ) -> bool {
90
97
debug ! ( "is_promotable: self={:?}" , self ) ;
@@ -133,7 +140,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
133
140
match context {
134
141
PlaceContext :: MutatingUse ( MutatingUseContext :: Store )
135
142
| PlaceContext :: MutatingUse ( MutatingUseContext :: Call ) => {
136
- * temp = TempState :: Defined { location, uses : 0 } ;
143
+ * temp = TempState :: Defined { location, uses : 0 , valid : Valid :: Unknown } ;
137
144
return ;
138
145
}
139
146
_ => { /* mark as unpromotable below */ }
@@ -188,7 +195,7 @@ pub fn collect_temps_and_candidates<'tcx>(
188
195
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
189
196
struct Validator < ' a , ' tcx > {
190
197
ccx : & ' a ConstCx < ' a , ' tcx > ,
191
- temps : & ' a IndexVec < Local , TempState > ,
198
+ temps : & ' a mut IndexVec < Local , TempState > ,
192
199
}
193
200
194
201
impl < ' a , ' tcx > std:: ops:: Deref for Validator < ' a , ' tcx > {
@@ -202,7 +209,7 @@ impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
202
209
struct Unpromotable ;
203
210
204
211
impl < ' tcx > Validator < ' _ , ' tcx > {
205
- fn validate_candidate ( & self , candidate : Candidate ) -> Result < ( ) , Unpromotable > {
212
+ fn validate_candidate ( & mut self , candidate : Candidate ) -> Result < ( ) , Unpromotable > {
206
213
let loc = candidate. location ;
207
214
let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
208
215
match & statement. kind {
@@ -234,7 +241,7 @@ impl<'tcx> Validator<'_, 'tcx> {
234
241
}
235
242
236
243
// FIXME(eddyb) maybe cache this?
237
- fn qualif_local < Q : qualifs:: Qualif > ( & self , local : Local ) -> bool {
244
+ fn qualif_local < Q : qualifs:: Qualif > ( & mut self , local : Local ) -> bool {
238
245
if let TempState :: Defined { location : loc, .. } = self . temps [ local] {
239
246
let num_stmts = self . body [ loc. block ] . statements . len ( ) ;
240
247
@@ -272,40 +279,62 @@ impl<'tcx> Validator<'_, 'tcx> {
272
279
}
273
280
}
274
281
275
- // FIXME(eddyb) maybe cache this?
276
- fn validate_local ( & self , local : Local ) -> Result < ( ) , Unpromotable > {
277
- if let TempState :: Defined { location : loc, .. } = self . temps [ local] {
278
- let block = & self . body [ loc. block ] ;
279
- let num_stmts = block. statements . len ( ) ;
280
-
281
- if loc. statement_index < num_stmts {
282
- let statement = & block. statements [ loc. statement_index ] ;
283
- match & statement. kind {
284
- StatementKind :: Assign ( box ( _, rhs) ) => self . validate_rvalue ( rhs) ,
285
- _ => {
286
- span_bug ! (
287
- statement. source_info. span,
288
- "{:?} is not an assignment" ,
289
- statement
290
- ) ;
291
- }
292
- }
293
- } else {
294
- let terminator = block. terminator ( ) ;
295
- match & terminator. kind {
296
- TerminatorKind :: Call { func, args, .. } => self . validate_call ( func, args) ,
297
- TerminatorKind :: Yield { .. } => Err ( Unpromotable ) ,
298
- kind => {
299
- span_bug ! ( terminator. source_info. span, "{:?} not promotable" , kind) ;
300
- }
282
+ fn validate_local ( & mut self , local : Local ) -> Result < ( ) , Unpromotable > {
283
+ if let TempState :: Defined { location : loc, uses, valid } = self . temps [ local] {
284
+ match valid {
285
+ Valid :: InValid => Err ( Unpromotable ) ,
286
+ Valid :: Validated => Ok ( ( ) ) ,
287
+ Valid :: Unknown => {
288
+ let ok = {
289
+ let block = & self . body [ loc. block ] ;
290
+ let num_stmts = block. statements . len ( ) ;
291
+
292
+ if loc. statement_index < num_stmts {
293
+ let statement = & block. statements [ loc. statement_index ] ;
294
+ match & statement. kind {
295
+ StatementKind :: Assign ( box ( _, rhs) ) => self . validate_rvalue ( rhs) ,
296
+ _ => {
297
+ span_bug ! (
298
+ statement. source_info. span,
299
+ "{:?} is not an assignment" ,
300
+ statement
301
+ ) ;
302
+ }
303
+ }
304
+ } else {
305
+ let terminator = block. terminator ( ) ;
306
+ match & terminator. kind {
307
+ TerminatorKind :: Call { func, args, .. } => {
308
+ self . validate_call ( func, args)
309
+ }
310
+ TerminatorKind :: Yield { .. } => Err ( Unpromotable ) ,
311
+ kind => {
312
+ span_bug ! (
313
+ terminator. source_info. span,
314
+ "{:?} not promotable" ,
315
+ kind
316
+ ) ;
317
+ }
318
+ }
319
+ }
320
+ } ;
321
+ self . temps [ local] = TempState :: Defined {
322
+ location : loc,
323
+ uses,
324
+ valid : match ok {
325
+ Ok ( ( ) ) => Valid :: Validated ,
326
+ Err ( _) => Valid :: InValid ,
327
+ } ,
328
+ } ;
329
+ ok
301
330
}
302
331
}
303
332
} else {
304
333
Err ( Unpromotable )
305
334
}
306
335
}
307
336
308
- fn validate_place ( & self , place : PlaceRef < ' tcx > ) -> Result < ( ) , Unpromotable > {
337
+ fn validate_place ( & mut self , place : PlaceRef < ' tcx > ) -> Result < ( ) , Unpromotable > {
309
338
match place. last_projection ( ) {
310
339
None => self . validate_local ( place. local ) ,
311
340
Some ( ( place_base, elem) ) => {
@@ -417,7 +446,7 @@ impl<'tcx> Validator<'_, 'tcx> {
417
446
}
418
447
}
419
448
420
- fn validate_operand ( & self , operand : & Operand < ' tcx > ) -> Result < ( ) , Unpromotable > {
449
+ fn validate_operand ( & mut self , operand : & Operand < ' tcx > ) -> Result < ( ) , Unpromotable > {
421
450
match operand {
422
451
Operand :: Copy ( place) | Operand :: Move ( place) => self . validate_place ( place. as_ref ( ) ) ,
423
452
@@ -447,7 +476,7 @@ impl<'tcx> Validator<'_, 'tcx> {
447
476
}
448
477
}
449
478
450
- fn validate_ref ( & self , kind : BorrowKind , place : & Place < ' tcx > ) -> Result < ( ) , Unpromotable > {
479
+ fn validate_ref ( & mut self , kind : BorrowKind , place : & Place < ' tcx > ) -> Result < ( ) , Unpromotable > {
451
480
match kind {
452
481
// Reject these borrow types just to be safe.
453
482
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
@@ -480,7 +509,7 @@ impl<'tcx> Validator<'_, 'tcx> {
480
509
Ok ( ( ) )
481
510
}
482
511
483
- fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
512
+ fn validate_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
484
513
match rvalue {
485
514
Rvalue :: Use ( operand) | Rvalue :: Repeat ( operand, _) => {
486
515
self . validate_operand ( operand) ?;
@@ -623,7 +652,7 @@ impl<'tcx> Validator<'_, 'tcx> {
623
652
}
624
653
625
654
fn validate_call (
626
- & self ,
655
+ & mut self ,
627
656
callee : & Operand < ' tcx > ,
628
657
args : & [ Operand < ' tcx > ] ,
629
658
) -> Result < ( ) , Unpromotable > {
@@ -665,10 +694,10 @@ impl<'tcx> Validator<'_, 'tcx> {
665
694
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
666
695
pub fn validate_candidates (
667
696
ccx : & ConstCx < ' _ , ' _ > ,
668
- temps : & IndexVec < Local , TempState > ,
697
+ temps : & mut IndexVec < Local , TempState > ,
669
698
candidates : & [ Candidate ] ,
670
699
) -> Vec < Candidate > {
671
- let validator = Validator { ccx, temps } ;
700
+ let mut validator = Validator { ccx, temps } ;
672
701
673
702
candidates
674
703
. iter ( )
@@ -720,7 +749,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
720
749
fn promote_temp ( & mut self , temp : Local ) -> Local {
721
750
let old_keep_original = self . keep_original ;
722
751
let loc = match self . temps [ temp] {
723
- TempState :: Defined { location, uses } if uses > 0 => {
752
+ TempState :: Defined { location, uses, .. } if uses > 0 => {
724
753
if uses > 1 {
725
754
self . keep_original = true ;
726
755
}
0 commit comments