@@ -94,18 +94,31 @@ impl fmt::Display for Mode {
9494 }
9595}
9696
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 > ,
98113 mode : Mode ,
99114 span : Span ,
100115 def_id : DefId ,
101116 mir : & ' a Mir < ' tcx > ,
102117 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 ,
107120 temp_promotion_state : IndexVec < Local , TempState > ,
108- promotion_candidates : Vec < Candidate >
121+ promotion_candidates : Vec < Candidate > ,
109122}
110123
111124macro_rules! unleash_miri {
@@ -145,8 +158,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
145158 rpo,
146159 tcx,
147160 param_env,
148- local_qualif,
149- qualif : Qualif :: empty ( ) ,
161+ state : State {
162+ local_qualif,
163+ qualif : Qualif :: empty ( ) ,
164+ } ,
150165 temp_promotion_state : temps,
151166 promotion_candidates : vec ! [ ]
152167 }
@@ -157,7 +172,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
157172 // slightly pointless (even with feature-gating).
158173 fn not_const ( & mut self ) {
159174 unleash_miri ! ( self ) ;
160- self . add ( Qualif :: NOT_CONST ) ;
175+ self . state . add ( Qualif :: NOT_CONST ) ;
161176 if self . mode != Mode :: Fn {
162177 let mut err = struct_span_err ! (
163178 self . tcx. sess,
@@ -176,31 +191,26 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
176191 }
177192 }
178193
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.
185195 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 ) ;
188198 }
189199
190- /// Within the provided closure, `self.qualif` will start
200+ /// Within the provided closure, `self.state. qualif` will start
191201 /// out empty, and its value after the closure returns will
192202 /// be combined with the value before the call to nest.
193203 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 ( ) ;
196206 f ( self ) ;
197- self . add ( original) ;
207+ self . state . add ( original) ;
198208 }
199209
200210 /// Assign the current qualification to the given destination.
201211 fn assign ( & mut self , dest : & Place < ' tcx > , location : Location ) {
202212 trace ! ( "assign: {:?}" , dest) ;
203- let qualif = self . qualif ;
213+ let qualif = self . state . qualif ;
204214 let span = self . span ;
205215 let store = |slot : & mut Option < Qualif > | {
206216 if slot. is_some ( ) {
@@ -215,7 +225,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
215225 if self . mir . local_kind ( index) == LocalKind :: Temp
216226 && self . temp_promotion_state [ index] . is_promotable ( ) {
217227 debug ! ( "store to promotable temp {:?} ({:?})" , index, qualif) ;
218- store ( & mut self . local_qualif [ index] ) ;
228+ store ( & mut self . state . local_qualif [ index] ) ;
219229 }
220230 }
221231 return ;
@@ -253,14 +263,14 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
253263 }
254264 } ;
255265 debug ! ( "store to var {:?}" , index) ;
256- match & mut self . local_qualif [ index] {
266+ match & mut self . state . local_qualif [ index] {
257267 // this is overly restrictive, because even full assignments do not clear the qualif
258268 // While we could special case full assignments, this would be inconsistent with
259269 // aggregates where we overwrite all fields via assignments, which would not get
260270 // that feature.
261- Some ( ref mut qualif) => * qualif = * qualif | self . qualif ,
271+ Some ( ref mut qualif) => * qualif = * qualif | self . state . qualif ,
262272 // insert new qualification
263- qualif @ None => * qualif = Some ( self . qualif ) ,
273+ qualif @ None => * qualif = Some ( self . state . qualif ) ,
264274 }
265275 }
266276
@@ -317,12 +327,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
317327 }
318328 }
319329
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 ) ;
321331
322332 // Account for errors in consts by using the
323333 // 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 ( ) ;
326336 let return_ty = mir. return_ty ( ) ;
327337 self . add_type ( return_ty) ;
328338 }
@@ -346,7 +356,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
346356 }
347357 }
348358
349- ( self . qualif , Lrc :: new ( promoted_temps) )
359+ ( self . state . qualif , Lrc :: new ( promoted_temps) )
350360 }
351361
352362 fn is_const_panic_fn ( & self , def_id : DefId ) -> bool {
@@ -355,7 +365,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx, 'tcx> {
355365 }
356366}
357367
358- /// Accumulates an Rvalue or Call's effects in self.qualif.
368+ /// Accumulates an Rvalue or Call's effects in self.state. qualif.
359369/// For functions (constant or not), it also records
360370/// candidates for promotion in promotion_candidates.
361371impl < ' a , ' tcx > Visitor < ' tcx > for Checker < ' a , ' tcx , ' tcx > {
@@ -370,22 +380,22 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
370380 self . not_const ( ) ;
371381 }
372382 LocalKind :: Var if self . mode == Mode :: Fn => {
373- self . add ( Qualif :: NOT_CONST ) ;
383+ self . state . add ( Qualif :: NOT_CONST ) ;
374384 }
375385 LocalKind :: Var |
376386 LocalKind :: Arg |
377387 LocalKind :: Temp => {
378388 if let LocalKind :: Arg = kind {
379- self . add ( Qualif :: FN_ARGUMENT ) ;
389+ self . state . add ( Qualif :: FN_ARGUMENT ) ;
380390 }
381391
382392 if !self . temp_promotion_state [ local] . is_promotable ( ) {
383393 debug ! ( "visit_local: (not promotable) local={:?}" , local) ;
384- self . add ( Qualif :: NOT_PROMOTABLE ) ;
394+ self . state . add ( Qualif :: NOT_PROMOTABLE ) ;
385395 }
386396
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) ;
389399 } else {
390400 self . not_const ( ) ;
391401 }
@@ -411,7 +421,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
411421 "thread-local statics cannot be \
412422 accessed at compile-time") ;
413423 }
414- self . add ( Qualif :: NOT_CONST ) ;
424+ self . state . add ( Qualif :: NOT_CONST ) ;
415425 return ;
416426 }
417427
@@ -430,7 +440,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
430440 return ;
431441 }
432442 unleash_miri ! ( self ) ;
433- self . add ( Qualif :: NOT_CONST ) ;
443+ self . state . add ( Qualif :: NOT_CONST ) ;
434444
435445 if self . mode != Mode :: Fn {
436446 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> {
458468 this. not_const ( )
459469 } else {
460470 // just make sure this doesn't get promoted
461- this. add ( Qualif :: NOT_CONST ) ;
471+ this. state . add ( Qualif :: NOT_CONST ) ;
462472 }
463473 let base_ty = proj. base . ty ( this. mir , this. tcx ) . to_ty ( this. tcx ) ;
464474 match this. mode {
@@ -508,7 +518,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
508518 }
509519
510520 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 ) ;
512522 }
513523
514524 ProjectionElem :: Downcast ( ..) => {
@@ -529,7 +539,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
529539 Operand :: Move ( _) => {
530540 // Mark the consumed locals to indicate later drops are noops.
531541 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|
533543 q - Qualif :: NEEDS_DROP
534544 ) ;
535545 }
@@ -543,12 +553,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
543553 let ( bits, _) = self . tcx . at ( constant. span ) . mir_const_qualif ( * def_id) ;
544554
545555 let qualif = Qualif :: from_bits ( bits) . expect ( "invalid mir_const_qualif" ) ;
546- self . add ( qualif) ;
556+ self . state . add ( qualif) ;
547557
548558 // Just in case the type is more specific than
549559 // the definition, e.g., impl associated const
550560 // 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 ) ;
552562 }
553563 }
554564 }
@@ -630,7 +640,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
630640
631641 if forbidden_mut {
632642 unleash_miri ! ( self ) ;
633- self . add ( Qualif :: NOT_CONST ) ;
643+ self . state . add ( Qualif :: NOT_CONST ) ;
634644 if self . mode != Mode :: Fn {
635645 let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0017 ,
636646 "references in {}s may only refer \
@@ -654,11 +664,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
654664 // Constants cannot be borrowed if they contain interior mutability as
655665 // it means that our "silent insertion of statics" could change
656666 // initializer values (very bad).
657- if self . qualif . contains ( Qualif :: MUTABLE_INTERIOR ) {
667+ if self . state . qualif . contains ( Qualif :: MUTABLE_INTERIOR ) {
658668 // A reference of a MUTABLE_INTERIOR place is instead
659669 // NOT_CONST (see `if forbidden_mut` below), to avoid
660670 // duplicate errors (from reborrowing, for example).
661- self . qualif = self . qualif - Qualif :: MUTABLE_INTERIOR ;
671+ self . state . qualif = self . state . qualif - Qualif :: MUTABLE_INTERIOR ;
662672 if self . mode != Mode :: Fn {
663673 span_err ! ( self . tcx. sess, self . span, E0492 ,
664674 "cannot borrow a constant which may contain \
@@ -673,7 +683,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
673683 debug ! ( "visit_rvalue: forbidden_mut={:?}" , forbidden_mut) ;
674684 if forbidden_mut {
675685 unleash_miri ! ( self ) ;
676- self . add ( Qualif :: NOT_CONST ) ;
686+ self . state . add ( Qualif :: NOT_CONST ) ;
677687 } else {
678688 // We might have a candidate for promotion.
679689 let candidate = Candidate :: Ref ( location) ;
@@ -689,7 +699,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
689699 if let Place :: Local ( local) = * place {
690700 if self . mir . local_kind ( local) == LocalKind :: Temp {
691701 debug ! ( "visit_rvalue: local={:?}" , local) ;
692- if let Some ( qualif) = self . local_qualif [ local] {
702+ if let Some ( qualif) = self . state . local_qualif [ local] {
693703 // `forbidden_mut` is false, so we can safely ignore
694704 // `MUTABLE_INTERIOR` from the local's qualifications.
695705 // This allows borrowing fields which don't have
@@ -716,7 +726,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
716726 unleash_miri ! ( self ) ;
717727 if let Mode :: Fn = self . mode {
718728 // in normal functions, mark such casts as not promotable
719- self . add ( Qualif :: NOT_CONST ) ;
729+ self . state . add ( Qualif :: NOT_CONST ) ;
720730 } else if !self . tcx . features ( ) . const_raw_ptr_to_usize_cast {
721731 // in const fn and constants require the feature gate
722732 // FIXME: make it unsafe inside const fn and constants
@@ -744,7 +754,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
744754 unleash_miri ! ( self ) ;
745755 if let Mode :: Fn = self . mode {
746756 // raw pointer operations are not allowed inside promoteds
747- self . add ( Qualif :: NOT_CONST ) ;
757+ self . state . add ( Qualif :: NOT_CONST ) ;
748758 } else if !self . tcx . features ( ) . const_compare_raw_pointers {
749759 // require the feature gate inside constants and const fn
750760 // FIXME: make it unsafe to use these operations
@@ -761,7 +771,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
761771
762772 Rvalue :: NullaryOp ( NullOp :: Box , _) => {
763773 unleash_miri ! ( self ) ;
764- self . add ( Qualif :: NOT_CONST ) ;
774+ self . state . add ( Qualif :: NOT_CONST ) ;
765775 if self . mode != Mode :: Fn {
766776 let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0010 ,
767777 "allocations are not allowed in {}s" , self . mode) ;
@@ -781,13 +791,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
781791 Rvalue :: Aggregate ( ref kind, _) => {
782792 if let AggregateKind :: Adt ( def, ..) = * * kind {
783793 if def. has_dtor ( self . tcx ) {
784- self . add ( Qualif :: NEEDS_DROP ) ;
794+ self . state . add ( Qualif :: NEEDS_DROP ) ;
785795 }
786796
787797 if Some ( def. did ) == self . tcx . lang_items ( ) . unsafe_cell_type ( ) {
788798 let ty = rvalue. ty ( self . mir , self . tcx ) ;
789799 self . add_type ( ty) ;
790- assert ! ( self . qualif. contains( Qualif :: MUTABLE_INTERIOR ) ) ;
800+ assert ! ( self . state . qualif. contains( Qualif :: MUTABLE_INTERIOR ) ) ;
791801 }
792802 }
793803 }
@@ -983,7 +993,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
983993 }
984994 let candidate = Candidate :: Argument { bb, index : i } ;
985995 if is_shuffle && i == 2 {
986- if this. qualif . is_empty ( ) {
996+ if this. state . qualif . is_empty ( ) {
987997 debug ! ( "visit_terminator_kind: candidate={:?}" , candidate) ;
988998 this. promotion_candidates . push ( candidate) ;
989999 } else {
@@ -1010,7 +1020,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
10101020 // which happens even without the user requesting it.
10111021 // We can error out with a hard error if the argument is not
10121022 // constant here.
1013- if ( this. qualif - Qualif :: NOT_PROMOTABLE ) . is_empty ( ) {
1023+ if ( this. state . qualif - Qualif :: NOT_PROMOTABLE ) . is_empty ( ) {
10141024 debug ! ( "visit_terminator_kind: candidate={:?}" , candidate) ;
10151025 this. promotion_candidates . push ( candidate) ;
10161026 } else {
@@ -1023,7 +1033,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
10231033
10241034 // non-const fn calls
10251035 if !is_const_fn {
1026- self . qualif = Qualif :: NOT_CONST ;
1036+ self . state . qualif = Qualif :: NOT_CONST ;
10271037 if self . mode != Mode :: Fn {
10281038 self . tcx . sess . delay_span_bug (
10291039 self . span ,
@@ -1034,16 +1044,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
10341044
10351045 if let Some ( ( ref dest, _) ) = * destination {
10361046 // 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 ;
10391049 } else {
10401050 // Be conservative about the returned value of a const fn.
10411051 let tcx = self . tcx ;
10421052 let ty = dest. ty ( self . mir , tcx) . to_ty ( tcx) ;
10431053 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 ;
10451055 } else {
1046- self . qualif = Qualif :: empty ( ) ;
1056+ self . state . qualif = Qualif :: empty ( ) ;
10471057 }
10481058 self . add_type ( ty) ;
10491059 }
@@ -1058,7 +1068,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx, 'tcx> {
10581068 // HACK(eddyb): emulate a bit of dataflow analysis,
10591069 // conservatively, that drop elaboration will do.
10601070 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 {
10621074 Some ( self . mir . local_decls [ local] . source_info . span )
10631075 } else {
10641076 None
0 commit comments