@@ -4,16 +4,22 @@ use rustc_hir::def_id::{DefId, LocalDefId};
4
4
use rustc_index:: bit_set:: BitSet ;
5
5
use rustc_macros:: LintDiagnostic ;
6
6
use 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,
8
9
} ;
9
10
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
10
11
use rustc_mir_dataflow:: impls:: MaybeInitializedPlaces ;
11
- use rustc_mir_dataflow:: move_paths:: MoveData ;
12
+ use rustc_mir_dataflow:: move_paths:: { MoveData , MovePathIndex } ;
12
13
use rustc_mir_dataflow:: { Analysis , MaybeReachable } ;
13
14
use rustc_session:: lint;
14
15
use rustc_span:: Span ;
15
16
use tracing:: debug;
16
17
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
+
17
23
fn drops_reachable_from_location < ' tcx > (
18
24
body : & Body < ' tcx > ,
19
25
block : BasicBlock ,
@@ -42,12 +48,7 @@ fn drops_reachable_from_location<'tcx>(
42
48
unwind : _,
43
49
replace : _,
44
50
} = & 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)
51
52
{
52
53
reachable. insert ( succ) ;
53
54
// 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>(
114
115
( ty_names, ty_spans)
115
116
}
116
117
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
+
117
136
pub ( crate ) fn run_lint < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId , body : & Body < ' tcx > ) {
118
137
if matches ! ( tcx. def_kind( def_id) , rustc_hir:: def:: DefKind :: SyntheticCoroutineBody ) {
119
138
// 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<
144
163
return ;
145
164
}
146
165
166
+ dump_mir ( tcx, false , "lint_tail_expr_drop_order" , & 0 as _ , body, |_, _| Ok ( ( ) ) ) ;
147
167
let param_env = tcx. param_env ( def_id) ;
148
168
let is_closure_like = tcx. is_closure_like ( def_id. to_def_id ( ) ) ;
149
169
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<
153
173
for & ( candidate, place) in & backwards_incompatible_drops {
154
174
maybe_init. seek_after_primary_effect ( candidate) ;
155
175
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 <_>>( ) ) ;
156
177
let maybe_init_in_future = maybe_init_in_future. clone ( ) ;
157
178
for block in drops_reachable_from_location ( body, candidate. block , place) . iter ( ) {
158
179
let data = & body. basic_blocks [ block] ;
180
+ debug ! ( ?candidate, ?block, "inspect" ) ;
159
181
maybe_init. seek_before_primary_effect ( Location {
160
182
block,
161
183
statement_index : data. statements . len ( ) ,
162
184
} ) ;
163
185
let MaybeReachable :: Reachable ( maybe_init_now) = maybe_init. get ( ) else { continue } ;
164
186
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 <_>>( ) ) ;
165
188
locals_dropped. subtract ( maybe_init_now) ;
189
+ debug ! ( locals_dropped = ?locals_dropped. iter( ) . map( |idx| & move_data. move_paths[ idx] ) . collect:: <Vec <_>>( ) ) ;
166
190
for path_idx in locals_dropped. iter ( ) {
167
191
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) {
169
197
continue ;
170
198
}
171
199
let dropped_local = move_path. place . local ;
0 commit comments