@@ -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