33use rustc_errors:: { struct_span_err, Applicability , Diagnostic , ErrorReported } ;
44use rustc_hir:: def_id:: DefId ;
55use rustc_hir:: { self as hir, HirId , LangItem } ;
6+ use rustc_index:: bit_set:: BitSet ;
67use rustc_infer:: infer:: TyCtxtInferExt ;
78use rustc_infer:: traits:: { ImplSource , Obligation , ObligationCause } ;
89use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
@@ -188,6 +189,9 @@ pub struct Validator<'mir, 'tcx> {
188189 /// The span of the current statement.
189190 span : Span ,
190191
192+ /// A set that stores for each local whether it has a `StorageDead` for it somewhere.
193+ local_has_storage_dead : Option < BitSet < Local > > ,
194+
191195 error_emitted : Option < ErrorReported > ,
192196 secondary_errors : Vec < Diagnostic > ,
193197}
@@ -206,6 +210,7 @@ impl Validator<'mir, 'tcx> {
206210 span : ccx. body . span ,
207211 ccx,
208212 qualifs : Default :: default ( ) ,
213+ local_has_storage_dead : None ,
209214 error_emitted : None ,
210215 secondary_errors : Vec :: new ( ) ,
211216 }
@@ -282,6 +287,27 @@ impl Validator<'mir, 'tcx> {
282287 }
283288 }
284289
290+ fn local_has_storage_dead ( & mut self , local : Local ) -> bool {
291+ let ccx = self . ccx ;
292+ self . local_has_storage_dead
293+ . get_or_insert_with ( || {
294+ struct StorageDeads {
295+ locals : BitSet < Local > ,
296+ }
297+ impl Visitor < ' tcx > for StorageDeads {
298+ fn visit_statement ( & mut self , stmt : & Statement < ' tcx > , _: Location ) {
299+ if let StatementKind :: StorageDead ( l) = stmt. kind {
300+ self . locals . insert ( l) ;
301+ }
302+ }
303+ }
304+ let mut v = StorageDeads { locals : BitSet :: new_empty ( ccx. body . local_decls . len ( ) ) } ;
305+ v. visit_body ( ccx. body ) ;
306+ v. locals
307+ } )
308+ . contains ( local)
309+ }
310+
285311 pub fn qualifs_in_return_place ( & mut self ) -> ConstQualifs {
286312 self . qualifs . in_return_place ( self . ccx , self . error_emitted )
287313 }
@@ -556,7 +582,13 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
556582 ) ;
557583
558584 if borrowed_place_has_mut_interior {
559- self . check_op ( ops:: CellBorrow ) ;
585+ // Locals without StorageDead follow the "trailing expression" rule, meaning
586+ // they are essentially anonymous static items themselves.
587+ if self . local_has_storage_dead ( place. local ) {
588+ self . check_op ( ops:: CellBorrowBehindRef ) ;
589+ } else {
590+ self . check_op ( ops:: CellBorrow ) ;
591+ }
560592 }
561593 }
562594
0 commit comments