@@ -4,16 +4,22 @@ use rustc_hir::def_id::{DefId, LocalDefId};
44use  rustc_index:: bit_set:: BitSet ; 
55use  rustc_macros:: LintDiagnostic ; 
66use  rustc_middle:: mir:: { 
7-     BasicBlock ,  Body ,  ClearCrossCrate ,  Local ,  Location ,  Place ,  StatementKind ,  TerminatorKind , 
7+     BasicBlock ,  Body ,  ClearCrossCrate ,  Local ,  Location ,  Place ,  ProjectionElem ,  StatementKind , 
8+     TerminatorKind ,  dump_mir, 
89} ; 
910use  rustc_middle:: ty:: { self ,  Ty ,  TyCtxt } ; 
1011use  rustc_mir_dataflow:: impls:: MaybeInitializedPlaces ; 
11- use  rustc_mir_dataflow:: move_paths:: MoveData ; 
12+ use  rustc_mir_dataflow:: move_paths:: { MoveData ,   MovePathIndex } ; 
1213use  rustc_mir_dataflow:: { Analysis ,  MaybeReachable } ; 
1314use  rustc_session:: lint; 
1415use  rustc_span:: Span ; 
1516use  tracing:: debug; 
1617
18+ fn  place_has_common_prefix < ' tcx > ( left :  & Place < ' tcx > ,  right :  & Place < ' tcx > )  -> bool  { 
19+     left. local  == right. local 
20+         && left. projection . iter ( ) . zip ( right. projection ) . all ( |( left,  right) | left == right) 
21+ } 
22+ 
1723fn  drops_reachable_from_location < ' tcx > ( 
1824    body :  & Body < ' tcx > , 
1925    block :  BasicBlock , 
@@ -42,12 +48,7 @@ fn drops_reachable_from_location<'tcx>(
4248                        unwind :  _, 
4349                        replace :  _, 
4450                    }  = & terminator. kind 
45-                     && dropped_place. local  == place. local 
46-                     && dropped_place
47-                         . projection 
48-                         . iter ( ) 
49-                         . zip ( place. projection ) 
50-                         . all ( |( dropped,  linted) | dropped == linted) 
51+                     && place_has_common_prefix ( dropped_place,  place) 
5152                { 
5253                    reachable. insert ( succ) ; 
5354                    // Now we have discovered a simple control flow path from a future drop point 
@@ -114,6 +115,24 @@ fn extract_component_with_significant_dtor<'tcx>(
114115    ( ty_names,  ty_spans) 
115116} 
116117
118+ fn  place_descendent_of_bids < ' tcx > ( 
119+     mut  idx :  MovePathIndex , 
120+     move_data :  & MoveData < ' tcx > , 
121+     bids :  & UnordSet < & Place < ' tcx > > , 
122+ )  -> bool  { 
123+     loop  { 
124+         let  path = & move_data. move_paths [ idx] ; 
125+         if  bids. contains ( & path. place )  { 
126+             return  true ; 
127+         } 
128+         if  let  Some ( parent)  = path. parent  { 
129+             idx = parent; 
130+         }  else  { 
131+             return  false ; 
132+         } 
133+     } 
134+ } 
135+ 
117136pub ( crate )  fn  run_lint < ' tcx > ( tcx :  TyCtxt < ' tcx > ,  def_id :  LocalDefId ,  body :  & Body < ' tcx > )  { 
118137    if  matches ! ( tcx. def_kind( def_id) ,  rustc_hir:: def:: DefKind :: SyntheticCoroutineBody )  { 
119138        // A synthetic coroutine has no HIR body and it is enough to just analyse the original body 
@@ -144,6 +163,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
144163        return ; 
145164    } 
146165
166+     dump_mir ( tcx,  false ,  "lint_tail_expr_drop_order" ,  & 0  as  _ ,  body,  |_,  _| Ok ( ( ) ) ) ; 
147167    let  param_env = tcx. param_env ( def_id) ; 
148168    let  is_closure_like = tcx. is_closure_like ( def_id. to_def_id ( ) ) ; 
149169    let  move_data = MoveData :: gather_moves ( body,  tcx,  param_env,  |_| true ) ; 
@@ -153,19 +173,27 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
153173    for  & ( candidate,  place)  in  & backwards_incompatible_drops { 
154174        maybe_init. seek_after_primary_effect ( candidate) ; 
155175        let  MaybeReachable :: Reachable ( maybe_init_in_future)  = maybe_init. get ( )  else  {  continue  } ; 
176+         debug ! ( maybe_init_in_future = ?maybe_init_in_future. iter( ) . map( |idx| & move_data. move_paths[ idx] ) . collect:: <Vec <_>>( ) ) ; 
156177        let  maybe_init_in_future = maybe_init_in_future. clone ( ) ; 
157178        for  block in  drops_reachable_from_location ( body,  candidate. block ,  place) . iter ( )  { 
158179            let  data = & body. basic_blocks [ block] ; 
180+             debug ! ( ?candidate,  ?block,  "inspect" ) ; 
159181            maybe_init. seek_before_primary_effect ( Location  { 
160182                block, 
161183                statement_index :  data. statements . len ( ) , 
162184            } ) ; 
163185            let  MaybeReachable :: Reachable ( maybe_init_now)  = maybe_init. get ( )  else  {  continue  } ; 
164186            let  mut  locals_dropped = maybe_init_in_future. clone ( ) ; 
187+             debug ! ( maybe_init_now = ?maybe_init_now. iter( ) . map( |idx| & move_data. move_paths[ idx] ) . collect:: <Vec <_>>( ) ) ; 
165188            locals_dropped. subtract ( maybe_init_now) ; 
189+             debug ! ( locals_dropped = ?locals_dropped. iter( ) . map( |idx| & move_data. move_paths[ idx] ) . collect:: <Vec <_>>( ) ) ; 
166190            for  path_idx in  locals_dropped. iter ( )  { 
167191                let  move_path = & move_data. move_paths [ path_idx] ; 
168-                 if  bid_places. contains ( & move_path. place )  { 
192+                 if  let  [ ..,  ProjectionElem :: Downcast ( _,  _) ]  = * * move_path. place . projection  { 
193+                     debug ! ( ?move_path. place,  "skip downcast which is not a real place" ) ; 
194+                     continue ; 
195+                 } 
196+                 if  place_descendent_of_bids ( path_idx,  & move_data,  & bid_places)  { 
169197                    continue ; 
170198                } 
171199                let  dropped_local = move_path. place . local ; 
0 commit comments