@@ -94,18 +94,31 @@ impl fmt::Display for Mode {
94
94
}
95
95
}
96
96
97
- struct Checker < ' a , ' gcx : ' a +' tcx , ' tcx : ' a > {
97
+ struct State {
98
+ local_qualif : IndexVec < Local , Option < Qualif > > ,
99
+
100
+ qualif : Qualif ,
101
+ }
102
+
103
+ impl State {
104
+ /// Add the given qualification to self.qualif.
105
+ fn add ( & mut self , qualif : Qualif ) {
106
+ self . qualif = self . qualif | qualif;
107
+ }
108
+ }
109
+
110
+ struct Checker < ' a , ' gcx , ' tcx > {
111
+ tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
112
+ param_env : ty:: ParamEnv < ' tcx > ,
98
113
mode : Mode ,
99
114
span : Span ,
100
115
def_id : DefId ,
101
116
mir : & ' a Mir < ' tcx > ,
102
117
rpo : ReversePostorder < ' a , ' tcx > ,
103
- tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
104
- param_env : ty:: ParamEnv < ' tcx > ,
105
- local_qualif : IndexVec < Local , Option < Qualif > > ,
106
- qualif : Qualif ,
118
+
119
+ state : State ,
107
120
temp_promotion_state : IndexVec < Local , TempState > ,
108
- promotion_candidates : Vec < Candidate >
121
+ promotion_candidates : Vec < Candidate > ,
109
122
}
110
123
111
124
macro_rules! unleash_miri {
@@ -145,8 +158,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
145
158
rpo,
146
159
tcx,
147
160
param_env,
148
- local_qualif,
149
- qualif : Qualif :: empty ( ) ,
161
+ state : State {
162
+ local_qualif,
163
+ qualif : Qualif :: empty ( ) ,
164
+ } ,
150
165
temp_promotion_state : temps,
151
166
promotion_candidates : vec ! [ ]
152
167
}
@@ -157,7 +172,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
157
172
// slightly pointless (even with feature-gating).
158
173
fn not_const ( & mut self ) {
159
174
unleash_miri ! ( self ) ;
160
- self . add ( Qualif :: NOT_CONST ) ;
175
+ self . state . add ( Qualif :: NOT_CONST ) ;
161
176
if self . mode != Mode :: Fn {
162
177
let mut err = struct_span_err ! (
163
178
self . tcx. sess,
@@ -176,31 +191,26 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
176
191
}
177
192
}
178
193
179
- /// Adds the given qualification to `self.qualif`.
180
- fn add ( & mut self , qualif : Qualif ) {
181
- self . qualif = self . qualif | qualif;
182
- }
183
-
184
- /// Adds the given type's qualification to `self.qualif`.
194
+ /// Adds the given type's qualification to self.state.qualif.
185
195
fn add_type ( & mut self , ty : Ty < ' tcx > ) {
186
- self . add ( Qualif :: MUTABLE_INTERIOR | Qualif :: NEEDS_DROP ) ;
187
- self . qualif . restrict ( ty, self . tcx , self . param_env ) ;
196
+ self . state . add ( Qualif :: MUTABLE_INTERIOR | Qualif :: NEEDS_DROP ) ;
197
+ self . state . qualif . restrict ( ty, self . tcx , self . param_env ) ;
188
198
}
189
199
190
- /// Within the provided closure, `self.qualif` will start
200
+ /// Within the provided closure, `self.state. qualif` will start
191
201
/// out empty, and its value after the closure returns will
192
202
/// be combined with the value before the call to nest.
193
203
fn nest < F : FnOnce ( & mut Self ) > ( & mut self , f : F ) {
194
- let original = self . qualif ;
195
- self . qualif = Qualif :: empty ( ) ;
204
+ let original = self . state . qualif ;
205
+ self . state . qualif = Qualif :: empty ( ) ;
196
206
f ( self ) ;
197
- self . add ( original) ;
207
+ self . state . add ( original) ;
198
208
}
199
209
200
210
/// Assign the current qualification to the given destination.
201
211
fn assign ( & mut self , dest : & Place < ' tcx > , location : Location ) {
202
212
trace ! ( "assign: {:?}" , dest) ;
203
- let qualif = self . qualif ;
213
+ let qualif = self . state . qualif ;
204
214
let span = self . span ;
205
215
let store = |slot : & mut Option < Qualif > | {
206
216
if slot. is_some ( ) {
@@ -215,7 +225,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
215
225
if self . mir . local_kind ( index) == LocalKind :: Temp
216
226
&& self . temp_promotion_state [ index] . is_promotable ( ) {
217
227
debug ! ( "store to promotable temp {:?} ({:?})" , index, qualif) ;
218
- store ( & mut self . local_qualif [ index] ) ;
228
+ store ( & mut self . state . local_qualif [ index] ) ;
219
229
}
220
230
}
221
231
return ;
@@ -253,14 +263,14 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
253
263
}
254
264
} ;
255
265
debug ! ( "store to var {:?}" , index) ;
256
- match & mut self . local_qualif [ index] {
266
+ match & mut self . state . local_qualif [ index] {
257
267
// this is overly restrictive, because even full assignments do not clear the qualif
258
268
// While we could special case full assignments, this would be inconsistent with
259
269
// aggregates where we overwrite all fields via assignments, which would not get
260
270
// that feature.
261
- Some ( ref mut qualif) => * qualif = * qualif | self . qualif ,
271
+ Some ( ref mut qualif) => * qualif = * qualif | self . state . qualif ,
262
272
// insert new qualification
263
- qualif @ None => * qualif = Some ( self . qualif ) ,
273
+ qualif @ None => * qualif = Some ( self . state . qualif ) ,
264
274
}
265
275
}
266
276
@@ -317,12 +327,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
317
327
}
318
328
}
319
329
320
- self . qualif = self . local_qualif [ RETURN_PLACE ] . unwrap_or ( Qualif :: NOT_CONST ) ;
330
+ self . state . qualif = self . state . local_qualif [ RETURN_PLACE ] . unwrap_or ( Qualif :: NOT_CONST ) ;
321
331
322
332
// Account for errors in consts by using the
323
333
// conservative type qualification instead.
324
- if self . qualif . intersects ( Qualif :: CONST_ERROR ) {
325
- self . qualif = Qualif :: empty ( ) ;
334
+ if self . state . qualif . intersects ( Qualif :: CONST_ERROR ) {
335
+ self . state . qualif = Qualif :: empty ( ) ;
326
336
let return_ty = mir. return_ty ( ) ;
327
337
self . add_type ( return_ty) ;
328
338
}
@@ -346,7 +356,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
346
356
}
347
357
}
348
358
349
- ( self . qualif , Lrc :: new ( promoted_temps) )
359
+ ( self . state . qualif , Lrc :: new ( promoted_temps) )
350
360
}
351
361
352
362
fn is_const_panic_fn ( & self , def_id : DefId ) -> bool {
@@ -355,7 +365,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
355
365
}
356
366
}
357
367
358
- /// Accumulates an Rvalue or Call's effects in self.qualif.
368
+ /// Accumulates an Rvalue or Call's effects in self.state. qualif.
359
369
/// For functions (constant or not), it also records
360
370
/// candidates for promotion in promotion_candidates.
361
371
impl < ' a , ' tcx > Visitor < ' tcx > for Checker < ' a , ' tcx , ' tcx > {
@@ -370,22 +380,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
370
380
self . not_const ( ) ;
371
381
}
372
382
LocalKind :: Var if self . mode == Mode :: Fn => {
373
- self . add ( Qualif :: NOT_CONST ) ;
383
+ self . state . add ( Qualif :: NOT_CONST ) ;
374
384
}
375
385
LocalKind :: Var |
376
386
LocalKind :: Arg |
377
387
LocalKind :: Temp => {
378
388
if let LocalKind :: Arg = kind {
379
- self . add ( Qualif :: FN_ARGUMENT ) ;
389
+ self . state . add ( Qualif :: FN_ARGUMENT ) ;
380
390
}
381
391
382
392
if !self . temp_promotion_state [ local] . is_promotable ( ) {
383
393
debug ! ( "visit_local: (not promotable) local={:?}" , local) ;
384
- self . add ( Qualif :: NOT_PROMOTABLE ) ;
394
+ self . state . add ( Qualif :: NOT_PROMOTABLE ) ;
385
395
}
386
396
387
- if let Some ( qualif) = self . local_qualif [ local] {
388
- self . add ( qualif) ;
397
+ if let Some ( qualif) = self . state . local_qualif [ local] {
398
+ self . state . add ( qualif) ;
389
399
} else {
390
400
self . not_const ( ) ;
391
401
}
@@ -411,7 +421,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
411
421
"thread-local statics cannot be \
412
422
accessed at compile-time") ;
413
423
}
414
- self . add ( Qualif :: NOT_CONST ) ;
424
+ self . state . add ( Qualif :: NOT_CONST ) ;
415
425
return ;
416
426
}
417
427
@@ -430,7 +440,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
430
440
return ;
431
441
}
432
442
unleash_miri ! ( self ) ;
433
- self . add ( Qualif :: NOT_CONST ) ;
443
+ self . state . add ( Qualif :: NOT_CONST ) ;
434
444
435
445
if self . mode != Mode :: Fn {
436
446
let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0013 ,
@@ -458,7 +468,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
458
468
this. not_const ( )
459
469
} else {
460
470
// just make sure this doesn't get promoted
461
- this. add ( Qualif :: NOT_CONST ) ;
471
+ this. state . add ( Qualif :: NOT_CONST ) ;
462
472
}
463
473
let base_ty = proj. base . ty ( this. mir , this. tcx ) . to_ty ( this. tcx ) ;
464
474
match this. mode {
@@ -508,7 +518,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
508
518
}
509
519
510
520
let ty = place. ty ( this. mir , this. tcx ) . to_ty ( this. tcx ) ;
511
- this. qualif . restrict ( ty, this. tcx , this. param_env ) ;
521
+ this. state . qualif . restrict ( ty, this. tcx , this. param_env ) ;
512
522
}
513
523
514
524
ProjectionElem :: Downcast ( ..) => {
@@ -529,7 +539,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
529
539
Operand :: Move ( _) => {
530
540
// Mark the consumed locals to indicate later drops are noops.
531
541
if let Operand :: Move ( Place :: Local ( local) ) = * operand {
532
- self . local_qualif [ local] = self . local_qualif [ local] . map ( |q|
542
+ self . state . local_qualif [ local] = self . state . local_qualif [ local] . map ( |q|
533
543
q - Qualif :: NEEDS_DROP
534
544
) ;
535
545
}
@@ -543,12 +553,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
543
553
let ( bits, _) = self . tcx . at ( constant. span ) . mir_const_qualif ( * def_id) ;
544
554
545
555
let qualif = Qualif :: from_bits ( bits) . expect ( "invalid mir_const_qualif" ) ;
546
- self . add ( qualif) ;
556
+ self . state . add ( qualif) ;
547
557
548
558
// Just in case the type is more specific than
549
559
// the definition, e.g., impl associated const
550
560
// with type parameters, take it into account.
551
- self . qualif . restrict ( constant. ty , self . tcx , self . param_env ) ;
561
+ self . state . qualif . restrict ( constant. ty , self . tcx , self . param_env ) ;
552
562
}
553
563
}
554
564
}
@@ -630,7 +640,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
630
640
631
641
if forbidden_mut {
632
642
unleash_miri ! ( self ) ;
633
- self . add ( Qualif :: NOT_CONST ) ;
643
+ self . state . add ( Qualif :: NOT_CONST ) ;
634
644
if self . mode != Mode :: Fn {
635
645
let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0017 ,
636
646
"references in {}s may only refer \
@@ -654,11 +664,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
654
664
// Constants cannot be borrowed if they contain interior mutability as
655
665
// it means that our "silent insertion of statics" could change
656
666
// initializer values (very bad).
657
- if self . qualif . contains ( Qualif :: MUTABLE_INTERIOR ) {
667
+ if self . state . qualif . contains ( Qualif :: MUTABLE_INTERIOR ) {
658
668
// A reference of a MUTABLE_INTERIOR place is instead
659
669
// NOT_CONST (see `if forbidden_mut` below), to avoid
660
670
// duplicate errors (from reborrowing, for example).
661
- self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
671
+ self . state . qualif = self . state . qualif - Qualif :: MUTABLE_INTERIOR ;
662
672
if self . mode != Mode :: Fn {
663
673
span_err ! ( self . tcx. sess, self . span, E0492 ,
664
674
"cannot borrow a constant which may contain \
@@ -673,7 +683,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
673
683
debug ! ( "visit_rvalue: forbidden_mut={:?}" , forbidden_mut) ;
674
684
if forbidden_mut {
675
685
unleash_miri ! ( self ) ;
676
- self . add ( Qualif :: NOT_CONST ) ;
686
+ self . state . add ( Qualif :: NOT_CONST ) ;
677
687
} else {
678
688
// We might have a candidate for promotion.
679
689
let candidate = Candidate :: Ref ( location) ;
@@ -689,7 +699,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
689
699
if let Place :: Local ( local) = * place {
690
700
if self . mir . local_kind ( local) == LocalKind :: Temp {
691
701
debug ! ( "visit_rvalue: local={:?}" , local) ;
692
- if let Some ( qualif) = self . local_qualif [ local] {
702
+ if let Some ( qualif) = self . state . local_qualif [ local] {
693
703
// `forbidden_mut` is false, so we can safely ignore
694
704
// `MUTABLE_INTERIOR` from the local's qualifications.
695
705
// This allows borrowing fields which don't have
@@ -716,7 +726,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
716
726
unleash_miri ! ( self ) ;
717
727
if let Mode :: Fn = self . mode {
718
728
// in normal functions, mark such casts as not promotable
719
- self . add ( Qualif :: NOT_CONST ) ;
729
+ self . state . add ( Qualif :: NOT_CONST ) ;
720
730
} else if !self . tcx . features ( ) . const_raw_ptr_to_usize_cast {
721
731
// in const fn and constants require the feature gate
722
732
// FIXME: make it unsafe inside const fn and constants
@@ -744,7 +754,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
744
754
unleash_miri ! ( self ) ;
745
755
if let Mode :: Fn = self . mode {
746
756
// raw pointer operations are not allowed inside promoteds
747
- self . add ( Qualif :: NOT_CONST ) ;
757
+ self . state . add ( Qualif :: NOT_CONST ) ;
748
758
} else if !self . tcx . features ( ) . const_compare_raw_pointers {
749
759
// require the feature gate inside constants and const fn
750
760
// FIXME: make it unsafe to use these operations
@@ -761,7 +771,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
761
771
762
772
Rvalue :: NullaryOp ( NullOp :: Box , _) => {
763
773
unleash_miri ! ( self ) ;
764
- self . add ( Qualif :: NOT_CONST ) ;
774
+ self . state . add ( Qualif :: NOT_CONST ) ;
765
775
if self . mode != Mode :: Fn {
766
776
let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0010 ,
767
777
"allocations are not allowed in {}s" , self . mode) ;
@@ -781,13 +791,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
781
791
Rvalue :: Aggregate ( ref kind, _) => {
782
792
if let AggregateKind :: Adt ( def, ..) = * * kind {
783
793
if def. has_dtor ( self . tcx ) {
784
- self . add ( Qualif :: NEEDS_DROP ) ;
794
+ self . state . add ( Qualif :: NEEDS_DROP ) ;
785
795
}
786
796
787
797
if Some ( def. did ) == self . tcx . lang_items ( ) . unsafe_cell_type ( ) {
788
798
let ty = rvalue. ty ( self . mir , self . tcx ) ;
789
799
self . add_type ( ty) ;
790
- assert ! ( self . qualif. contains( Qualif :: MUTABLE_INTERIOR ) ) ;
800
+ assert ! ( self . state . qualif. contains( Qualif :: MUTABLE_INTERIOR ) ) ;
791
801
}
792
802
}
793
803
}
@@ -983,7 +993,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
983
993
}
984
994
let candidate = Candidate :: Argument { bb, index : i } ;
985
995
if is_shuffle && i == 2 {
986
- if this. qualif . is_empty ( ) {
996
+ if this. state . qualif . is_empty ( ) {
987
997
debug ! ( "visit_terminator_kind: candidate={:?}" , candidate) ;
988
998
this. promotion_candidates . push ( candidate) ;
989
999
} else {
@@ -1010,7 +1020,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
1010
1020
// which happens even without the user requesting it.
1011
1021
// We can error out with a hard error if the argument is not
1012
1022
// constant here.
1013
- if ( this. qualif - Qualif :: NOT_PROMOTABLE ) . is_empty ( ) {
1023
+ if ( this. state . qualif - Qualif :: NOT_PROMOTABLE ) . is_empty ( ) {
1014
1024
debug ! ( "visit_terminator_kind: candidate={:?}" , candidate) ;
1015
1025
this. promotion_candidates . push ( candidate) ;
1016
1026
} else {
@@ -1023,7 +1033,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
1023
1033
1024
1034
// non-const fn calls
1025
1035
if !is_const_fn {
1026
- self . qualif = Qualif :: NOT_CONST ;
1036
+ self . state . qualif = Qualif :: NOT_CONST ;
1027
1037
if self . mode != Mode :: Fn {
1028
1038
self . tcx . sess . delay_span_bug (
1029
1039
self . span ,
@@ -1034,16 +1044,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
1034
1044
1035
1045
if let Some ( ( ref dest, _) ) = * destination {
1036
1046
// Avoid propagating irrelevant callee/argument qualifications.
1037
- if self . qualif . intersects ( Qualif :: CONST_ERROR ) {
1038
- self . qualif = Qualif :: NOT_CONST ;
1047
+ if self . state . qualif . intersects ( Qualif :: CONST_ERROR ) {
1048
+ self . state . qualif = Qualif :: NOT_CONST ;
1039
1049
} else {
1040
1050
// Be conservative about the returned value of a const fn.
1041
1051
let tcx = self . tcx ;
1042
1052
let ty = dest. ty ( self . mir , tcx) . to_ty ( tcx) ;
1043
1053
if is_const_fn && !is_promotable_const_fn && self . mode == Mode :: Fn {
1044
- self . qualif = Qualif :: NOT_PROMOTABLE ;
1054
+ self . state . qualif = Qualif :: NOT_PROMOTABLE ;
1045
1055
} else {
1046
- self . qualif = Qualif :: empty ( ) ;
1056
+ self . state . qualif = Qualif :: empty ( ) ;
1047
1057
}
1048
1058
self . add_type ( ty) ;
1049
1059
}
@@ -1058,7 +1068,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
1058
1068
// HACK(eddyb): emulate a bit of dataflow analysis,
1059
1069
// conservatively, that drop elaboration will do.
1060
1070
let needs_drop = if let Place :: Local ( local) = * place {
1061
- if self . local_qualif [ local] . map_or ( true , |q| q. contains ( Qualif :: NEEDS_DROP ) ) {
1071
+ let local_needs_drop = self . state . local_qualif [ local]
1072
+ . map_or ( true , |q| q. contains ( Qualif :: NEEDS_DROP ) ) ;
1073
+ if local_needs_drop {
1062
1074
Some ( self . mir . local_decls [ local] . source_info . span )
1063
1075
} else {
1064
1076
None
0 commit comments