16
16
#![ warn( unreachable_pub) ]
17
17
// tidy-alphabetical-end
18
18
19
+ use std:: borrow:: Cow ;
19
20
use std:: cell:: RefCell ;
20
21
use std:: marker:: PhantomData ;
21
22
use std:: ops:: { ControlFlow , Deref } ;
22
23
23
24
use rustc_abi:: FieldIdx ;
24
25
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
25
26
use rustc_data_structures:: graph:: dominators:: Dominators ;
27
+ use rustc_errors:: LintDiagnostic ;
26
28
use rustc_hir as hir;
29
+ use rustc_hir:: CRATE_HIR_ID ;
27
30
use rustc_hir:: def_id:: LocalDefId ;
28
31
use rustc_index:: bit_set:: { BitSet , MixedBitSet } ;
29
32
use rustc_index:: { IndexSlice , IndexVec } ;
@@ -43,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
43
46
InitIndex , InitLocation , LookupResult , MoveData , MovePathIndex ,
44
47
} ;
45
48
use rustc_mir_dataflow:: { Analysis , EntryStates , Results , ResultsVisitor , visit_results} ;
46
- use rustc_session:: lint:: builtin:: UNUSED_MUT ;
49
+ use rustc_session:: lint:: builtin:: { TAIL_EXPR_DROP_ORDER , UNUSED_MUT } ;
47
50
use rustc_span:: { Span , Symbol } ;
48
51
use smallvec:: SmallVec ;
49
52
use tracing:: { debug, instrument} ;
@@ -636,9 +639,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
636
639
| StatementKind :: Coverage ( ..)
637
640
// These do not actually affect borrowck
638
641
| StatementKind :: ConstEvalCounter
639
- // This do not affect borrowck
640
- | StatementKind :: BackwardIncompatibleDropHint { .. }
641
642
| StatementKind :: StorageLive ( ..) => { }
643
+ // This does not affect borrowck
644
+ StatementKind :: BackwardIncompatibleDropHint { place, reason : BackwardIncompatibleDropReason :: Edition2024 } => {
645
+ self . check_backward_incompatible_drop ( location, ( * * place, span) , state) ;
646
+ }
642
647
StatementKind :: StorageDead ( local) => {
643
648
self . access_place (
644
649
location,
@@ -1007,6 +1012,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1007
1012
}
1008
1013
}
1009
1014
1015
+ fn borrows_in_scope < ' s > (
1016
+ & self ,
1017
+ location : Location ,
1018
+ state : & ' s BorrowckDomain ,
1019
+ ) -> Cow < ' s , BitSet < BorrowIndex > > {
1020
+ if let Some ( polonius) = & self . polonius_output {
1021
+ // Use polonius output if it has been enabled.
1022
+ let location = self . location_table . start_index ( location) ;
1023
+ let mut polonius_output = BitSet :: new_empty ( self . borrow_set . len ( ) ) ;
1024
+ for & idx in polonius. errors_at ( location) {
1025
+ polonius_output. insert ( idx) ;
1026
+ }
1027
+ Cow :: Owned ( polonius_output)
1028
+ } else {
1029
+ Cow :: Borrowed ( & state. borrows )
1030
+ }
1031
+ }
1032
+
1010
1033
#[ instrument( level = "debug" , skip( self , state) ) ]
1011
1034
fn check_access_for_conflict (
1012
1035
& mut self ,
@@ -1018,18 +1041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1018
1041
) -> bool {
1019
1042
let mut error_reported = false ;
1020
1043
1021
- // Use polonius output if it has been enabled.
1022
- let mut polonius_output;
1023
- let borrows_in_scope = if let Some ( polonius) = & self . polonius_output {
1024
- let location = self . location_table . start_index ( location) ;
1025
- polonius_output = BitSet :: new_empty ( self . borrow_set . len ( ) ) ;
1026
- for & idx in polonius. errors_at ( location) {
1027
- polonius_output. insert ( idx) ;
1028
- }
1029
- & polonius_output
1030
- } else {
1031
- & state. borrows
1032
- } ;
1044
+ let borrows_in_scope = self . borrows_in_scope ( location, state) ;
1033
1045
1034
1046
each_borrow_involving_path (
1035
1047
self ,
@@ -1149,6 +1161,61 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1149
1161
error_reported
1150
1162
}
1151
1163
1164
+ /// Through #123739, backward incompatible drops (BIDs) are introduced.
1165
+ /// We would like to emit lints whether borrow checking fails at these future drop locations.
1166
+ #[ instrument( level = "debug" , skip( self , state) ) ]
1167
+ fn check_backward_incompatible_drop (
1168
+ & mut self ,
1169
+ location : Location ,
1170
+ ( place, place_span) : ( Place < ' tcx > , Span ) ,
1171
+ state : & BorrowckDomain ,
1172
+ ) {
1173
+ let tcx = self . infcx . tcx ;
1174
+ // If this type does not need `Drop`, then treat it like a `StorageDead`.
1175
+ // This is needed because we track the borrows of refs to thread locals,
1176
+ // and we'll ICE because we don't track borrows behind shared references.
1177
+ let sd = if place. ty ( self . body , tcx) . ty . needs_drop ( tcx, self . body . typing_env ( tcx) ) {
1178
+ AccessDepth :: Drop
1179
+ } else {
1180
+ AccessDepth :: Shallow ( None )
1181
+ } ;
1182
+
1183
+ let borrows_in_scope = self . borrows_in_scope ( location, state) ;
1184
+
1185
+ // This is a very simplified version of `Self::check_access_for_conflict`.
1186
+ // We are here checking on BIDs and specifically still-live borrows of data involving the BIDs.
1187
+ each_borrow_involving_path (
1188
+ self ,
1189
+ self . infcx . tcx ,
1190
+ self . body ,
1191
+ ( sd, place) ,
1192
+ self . borrow_set ,
1193
+ |borrow_index| borrows_in_scope. contains ( borrow_index) ,
1194
+ |this, _borrow_index, borrow| {
1195
+ if matches ! ( borrow. kind, BorrowKind :: Fake ( _) ) {
1196
+ return ControlFlow :: Continue ( ( ) ) ;
1197
+ }
1198
+ let borrowed = this. retrieve_borrow_spans ( borrow) . var_or_use_path_span ( ) ;
1199
+ let explain = this. explain_why_borrow_contains_point (
1200
+ location,
1201
+ borrow,
1202
+ Some ( ( WriteKind :: StorageDeadOrDrop , place) ) ,
1203
+ ) ;
1204
+ this. infcx . tcx . node_span_lint (
1205
+ TAIL_EXPR_DROP_ORDER ,
1206
+ CRATE_HIR_ID ,
1207
+ borrowed,
1208
+ |diag| {
1209
+ session_diagnostics:: TailExprDropOrder { borrowed } . decorate_lint ( diag) ;
1210
+ explain. add_explanation_to_diagnostic ( & this, diag, "" , None , None ) ;
1211
+ } ,
1212
+ ) ;
1213
+ // We may stop at the first case
1214
+ ControlFlow :: Break ( ( ) )
1215
+ } ,
1216
+ ) ;
1217
+ }
1218
+
1152
1219
fn mutate_place (
1153
1220
& mut self ,
1154
1221
location : Location ,
0 commit comments