1515#![ warn( unreachable_pub) ]
1616// tidy-alphabetical-end
1717
18+ use std:: borrow:: Cow ;
1819use std:: cell:: RefCell ;
1920use std:: marker:: PhantomData ;
2021use std:: ops:: Deref ;
2122
2223use rustc_abi:: FieldIdx ;
2324use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
2425use rustc_data_structures:: graph:: dominators:: Dominators ;
26+ use rustc_errors:: LintDiagnostic ;
2527use rustc_hir as hir;
28+ use rustc_hir:: CRATE_HIR_ID ;
2629use rustc_hir:: def_id:: LocalDefId ;
2730use rustc_index:: bit_set:: { BitSet , MixedBitSet } ;
2831use rustc_index:: { IndexSlice , IndexVec } ;
@@ -42,7 +45,7 @@ use rustc_mir_dataflow::move_paths::{
4245 InitIndex , InitLocation , LookupResult , MoveData , MovePathIndex ,
4346} ;
4447use rustc_mir_dataflow:: { Analysis , EntryStates , Results , ResultsVisitor , visit_results} ;
45- use rustc_session:: lint:: builtin:: UNUSED_MUT ;
48+ use rustc_session:: lint:: builtin:: { TAIL_EXPR_DROP_ORDER , UNUSED_MUT } ;
4649use rustc_span:: { Span , Symbol } ;
4750use smallvec:: SmallVec ;
4851use tracing:: { debug, instrument} ;
@@ -636,9 +639,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
636639 | StatementKind :: Coverage ( ..)
637640 // These do not actually affect borrowck
638641 | StatementKind :: ConstEvalCounter
639- // This do not affect borrowck
640- | StatementKind :: BackwardIncompatibleDropHint { .. }
641642 | 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+ }
642647 StatementKind :: StorageDead ( local) => {
643648 self . access_place (
644649 location,
@@ -1007,6 +1012,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
10071012 }
10081013 }
10091014
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+
10101033 #[ instrument( level = "debug" , skip( self , state) ) ]
10111034 fn check_access_for_conflict (
10121035 & mut self ,
@@ -1018,18 +1041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
10181041 ) -> bool {
10191042 let mut error_reported = false ;
10201043
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) ;
10331045
10341046 each_borrow_involving_path (
10351047 self ,
@@ -1149,6 +1161,69 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
11491161 error_reported
11501162 }
11511163
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 Control :: 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 (
1211+ this. infcx . tcx ,
1212+ this. body ,
1213+ & this. local_names ,
1214+ diag,
1215+ "" ,
1216+ None ,
1217+ None ,
1218+ ) ;
1219+ } ,
1220+ ) ;
1221+ // We may stop at the first case
1222+ Control :: Break
1223+ } ,
1224+ ) ;
1225+ }
1226+
11521227 fn mutate_place (
11531228 & mut self ,
11541229 location : Location ,
0 commit comments