33use rustc_errors:: struct_span_err;
44use rustc_hir:: lang_items;
55use rustc_hir:: { def_id:: DefId , HirId } ;
6- use rustc_index:: bit_set:: BitSet ;
76use rustc_infer:: infer:: TyCtxtInferExt ;
87use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
98use rustc_middle:: mir:: * ;
@@ -28,70 +27,100 @@ use crate::dataflow::{self, Analysis};
2827// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
2928// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
3029// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
31- pub type IndirectlyMutableResults < ' mir , ' tcx > =
30+ type IndirectlyMutableResults < ' mir , ' tcx > =
3231 dataflow:: ResultsCursor < ' mir , ' tcx , MaybeMutBorrowedLocals < ' mir , ' tcx > > ;
3332
34- struct QualifCursor < ' a , ' mir , ' tcx , Q : Qualif > {
35- cursor : dataflow:: ResultsCursor < ' mir , ' tcx , FlowSensitiveAnalysis < ' a , ' mir , ' tcx , Q > > ,
36- in_any_value_of_ty : BitSet < Local > ,
37- }
38-
39- impl < Q : Qualif > QualifCursor < ' a , ' mir , ' tcx , Q > {
40- pub fn new ( q : Q , ccx : & ' a ConstCx < ' mir , ' tcx > ) -> Self {
41- let cursor = FlowSensitiveAnalysis :: new ( q, ccx)
42- . into_engine ( ccx. tcx , ccx. body , ccx. def_id )
43- . iterate_to_fixpoint ( )
44- . into_results_cursor ( ccx. body ) ;
45-
46- let mut in_any_value_of_ty = BitSet :: new_empty ( ccx. body . local_decls . len ( ) ) ;
47- for ( local, decl) in ccx. body . local_decls . iter_enumerated ( ) {
48- if Q :: in_any_value_of_ty ( ccx, decl. ty ) {
49- in_any_value_of_ty. insert ( local) ;
50- }
51- }
33+ type QualifResults < ' mir , ' tcx , Q > =
34+ dataflow:: ResultsCursor < ' mir , ' tcx , FlowSensitiveAnalysis < ' mir , ' mir , ' tcx , Q > > ;
5235
53- QualifCursor { cursor, in_any_value_of_ty }
54- }
36+ #[ derive( Default ) ]
37+ pub struct Qualifs < ' mir , ' tcx > {
38+ has_mut_interior : Option < QualifResults < ' mir , ' tcx , HasMutInterior > > ,
39+ needs_drop : Option < QualifResults < ' mir , ' tcx , NeedsDrop > > ,
40+ indirectly_mutable : Option < IndirectlyMutableResults < ' mir , ' tcx > > ,
5541}
5642
57- pub struct Qualifs < ' a , ' mir , ' tcx > {
58- has_mut_interior : QualifCursor < ' a , ' mir , ' tcx , HasMutInterior > ,
59- needs_drop : QualifCursor < ' a , ' mir , ' tcx , NeedsDrop > ,
60- indirectly_mutable : IndirectlyMutableResults < ' mir , ' tcx > ,
61- }
62-
63- impl Qualifs < ' a , ' mir , ' tcx > {
64- fn indirectly_mutable ( & mut self , local : Local , location : Location ) -> bool {
65- self . indirectly_mutable . seek_before ( location) ;
66- self . indirectly_mutable . get ( ) . contains ( local)
43+ impl Qualifs < ' mir , ' tcx > {
44+ fn indirectly_mutable (
45+ & mut self ,
46+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
47+ local : Local ,
48+ location : Location ,
49+ ) -> bool {
50+ let indirectly_mutable = self . indirectly_mutable . get_or_insert_with ( || {
51+ let ConstCx { tcx, body, def_id, param_env, .. } = * ccx;
52+
53+ // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
54+ // allowed in a const.
55+ //
56+ // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
57+ // without breaking stable code?
58+ MaybeMutBorrowedLocals :: mut_borrows_only ( tcx, & body, param_env)
59+ . unsound_ignore_borrow_on_drop ( )
60+ . into_engine ( tcx, & body, def_id)
61+ . iterate_to_fixpoint ( )
62+ . into_results_cursor ( & body)
63+ } ) ;
64+
65+ indirectly_mutable. seek_before ( location) ;
66+ indirectly_mutable. get ( ) . contains ( local)
6767 }
6868
6969 /// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
7070 ///
7171 /// Only updates the cursor if absolutely necessary
72- fn needs_drop ( & mut self , local : Local , location : Location ) -> bool {
73- if !self . needs_drop . in_any_value_of_ty . contains ( local) {
72+ fn needs_drop (
73+ & mut self ,
74+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
75+ local : Local ,
76+ location : Location ,
77+ ) -> bool {
78+ let ty = ccx. body . local_decls [ local] . ty ;
79+ if !NeedsDrop :: in_any_value_of_ty ( ccx, ty) {
7480 return false ;
7581 }
7682
77- self . needs_drop . cursor . seek_before ( location) ;
78- self . needs_drop . cursor . get ( ) . contains ( local) || self . indirectly_mutable ( local, location)
83+ let needs_drop = self . needs_drop . get_or_insert_with ( || {
84+ let ConstCx { tcx, body, def_id, .. } = * ccx;
85+
86+ FlowSensitiveAnalysis :: new ( NeedsDrop , ccx)
87+ . into_engine ( tcx, & body, def_id)
88+ . iterate_to_fixpoint ( )
89+ . into_results_cursor ( & body)
90+ } ) ;
91+
92+ needs_drop. seek_before ( location) ;
93+ needs_drop. get ( ) . contains ( local) || self . indirectly_mutable ( ccx, local, location)
7994 }
8095
8196 /// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
8297 ///
8398 /// Only updates the cursor if absolutely necessary.
84- fn has_mut_interior ( & mut self , local : Local , location : Location ) -> bool {
85- if !self . has_mut_interior . in_any_value_of_ty . contains ( local) {
99+ fn has_mut_interior (
100+ & mut self ,
101+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
102+ local : Local ,
103+ location : Location ,
104+ ) -> bool {
105+ let ty = ccx. body . local_decls [ local] . ty ;
106+ if !HasMutInterior :: in_any_value_of_ty ( ccx, ty) {
86107 return false ;
87108 }
88109
89- self . has_mut_interior . cursor . seek_before ( location) ;
90- self . has_mut_interior . cursor . get ( ) . contains ( local)
91- || self . indirectly_mutable ( local, location)
110+ let has_mut_interior = self . has_mut_interior . get_or_insert_with ( || {
111+ let ConstCx { tcx, body, def_id, .. } = * ccx;
112+
113+ FlowSensitiveAnalysis :: new ( HasMutInterior , ccx)
114+ . into_engine ( tcx, & body, def_id)
115+ . iterate_to_fixpoint ( )
116+ . into_results_cursor ( & body)
117+ } ) ;
118+
119+ has_mut_interior. seek_before ( location) ;
120+ has_mut_interior. get ( ) . contains ( local) || self . indirectly_mutable ( ccx, local, location)
92121 }
93122
94- fn in_return_place ( & mut self , ccx : & ConstCx < ' _ , ' tcx > ) -> ConstQualifs {
123+ fn in_return_place ( & mut self , ccx : & ' mir ConstCx < ' mir , ' tcx > ) -> ConstQualifs {
95124 // Find the `Return` terminator if one exists.
96125 //
97126 // If no `Return` terminator exists, this MIR is divergent. Just return the conservative
@@ -114,49 +143,31 @@ impl Qualifs<'a, 'mir, 'tcx> {
114143 let return_loc = ccx. body . terminator_loc ( return_block) ;
115144
116145 ConstQualifs {
117- needs_drop : self . needs_drop ( RETURN_PLACE , return_loc) ,
118- has_mut_interior : self . has_mut_interior ( RETURN_PLACE , return_loc) ,
146+ needs_drop : self . needs_drop ( ccx , RETURN_PLACE , return_loc) ,
147+ has_mut_interior : self . has_mut_interior ( ccx , RETURN_PLACE , return_loc) ,
119148 }
120149 }
121150}
122151
123- pub struct Validator < ' a , ' mir , ' tcx > {
124- ccx : & ' a ConstCx < ' mir , ' tcx > ,
125- qualifs : Qualifs < ' a , ' mir , ' tcx > ,
152+ pub struct Validator < ' mir , ' tcx > {
153+ ccx : & ' mir ConstCx < ' mir , ' tcx > ,
154+ qualifs : Qualifs < ' mir , ' tcx > ,
126155
127156 /// The span of the current statement.
128157 span : Span ,
129158}
130159
131- impl Deref for Validator < ' _ , ' mir , ' tcx > {
160+ impl Deref for Validator < ' mir , ' tcx > {
132161 type Target = ConstCx < ' mir , ' tcx > ;
133162
134163 fn deref ( & self ) -> & Self :: Target {
135164 & self . ccx
136165 }
137166}
138167
139- impl Validator < ' a , ' mir , ' tcx > {
140- pub fn new ( ccx : & ' a ConstCx < ' mir , ' tcx > ) -> Self {
141- let ConstCx { tcx, body, def_id, param_env, .. } = * ccx;
142-
143- let needs_drop = QualifCursor :: new ( NeedsDrop , ccx) ;
144- let has_mut_interior = QualifCursor :: new ( HasMutInterior , ccx) ;
145-
146- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
147- // allowed in a const.
148- //
149- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
150- // without breaking stable code?
151- let indirectly_mutable = MaybeMutBorrowedLocals :: mut_borrows_only ( tcx, body, param_env)
152- . unsound_ignore_borrow_on_drop ( )
153- . into_engine ( tcx, body, def_id)
154- . iterate_to_fixpoint ( )
155- . into_results_cursor ( body) ;
156-
157- let qualifs = Qualifs { needs_drop, has_mut_interior, indirectly_mutable } ;
158-
159- Validator { span : ccx. body . span , ccx, qualifs }
168+ impl Validator < ' mir , ' tcx > {
169+ pub fn new ( ccx : & ' mir ConstCx < ' mir , ' tcx > ) -> Self {
170+ Validator { span : ccx. body . span , ccx, qualifs : Default :: default ( ) }
160171 }
161172
162173 pub fn check_body ( & mut self ) {
@@ -239,7 +250,7 @@ impl Validator<'a, 'mir, 'tcx> {
239250 }
240251}
241252
242- impl Visitor < ' tcx > for Validator < ' _ , ' mir , ' tcx > {
253+ impl Visitor < ' tcx > for Validator < ' mir , ' tcx > {
243254 fn visit_basic_block_data ( & mut self , bb : BasicBlock , block : & BasicBlockData < ' tcx > ) {
244255 trace ! ( "visit_basic_block_data: bb={:?} is_cleanup={:?}" , bb, block. is_cleanup) ;
245256
@@ -345,7 +356,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
345356 | Rvalue :: AddressOf ( Mutability :: Not , ref place) => {
346357 let borrowed_place_has_mut_interior = qualifs:: in_place :: < HasMutInterior , _ > (
347358 & self . ccx ,
348- & mut |local| self . qualifs . has_mut_interior ( local, location) ,
359+ & mut |local| self . qualifs . has_mut_interior ( self . ccx , local, location) ,
349360 place. as_ref ( ) ,
350361 ) ;
351362
@@ -571,7 +582,7 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
571582 let needs_drop = if let Some ( local) = dropped_place. as_local ( ) {
572583 // Use the span where the local was declared as the span of the drop error.
573584 err_span = self . body . local_decls [ local] . source_info . span ;
574- self . qualifs . needs_drop ( local, location)
585+ self . qualifs . needs_drop ( self . ccx , local, location)
575586 } else {
576587 true
577588 } ;
0 commit comments