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. 
128157span :  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