@@ -6,6 +6,7 @@ use rustc::hir::Node;
66use rustc:: hir:: def_id:: DefId ;
77use rustc:: infer:: InferCtxt ;
88use rustc:: lint:: builtin:: UNUSED_MUT ;
9+ use rustc:: lint:: builtin:: { MUTABLE_BORROW_RESERVATION_CONFLICT } ;
910use rustc:: middle:: borrowck:: SignalledError ;
1011use rustc:: mir:: { AggregateKind , BasicBlock , BorrowCheckResult , BorrowKind } ;
1112use rustc:: mir:: {
@@ -18,14 +19,15 @@ use rustc::ty::{self, TyCtxt};
1819
1920use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , Level } ;
2021use rustc_data_structures:: bit_set:: BitSet ;
21- use rustc_data_structures:: fx:: FxHashSet ;
22+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2223use rustc_data_structures:: graph:: dominators:: Dominators ;
2324use smallvec:: SmallVec ;
2425
25- use std:: rc:: Rc ;
2626use std:: collections:: BTreeMap ;
27+ use std:: mem;
28+ use std:: rc:: Rc ;
2729
28- use syntax_pos:: Span ;
30+ use syntax_pos:: { Span , DUMMY_SP } ;
2931
3032use crate :: dataflow:: indexes:: { BorrowIndex , InitIndex , MoveOutIndex , MovePathIndex } ;
3133use crate :: dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MoveError } ;
@@ -238,6 +240,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
238240 locals_are_invalidated_at_exit,
239241 access_place_error_reported : Default :: default ( ) ,
240242 reservation_error_reported : Default :: default ( ) ,
243+ reservation_warnings : Default :: default ( ) ,
241244 move_error_reported : BTreeMap :: new ( ) ,
242245 uninitialized_error_reported : Default :: default ( ) ,
243246 errors_buffer,
@@ -260,6 +263,29 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
260263 }
261264 mbcx. analyze_results ( & mut state) ; // entry point for DataflowResultsConsumer
262265
266+ // Convert any reservation warnings into lints.
267+ let reservation_warnings = mem:: replace ( & mut mbcx. reservation_warnings , Default :: default ( ) ) ;
268+ for ( _, ( place, span, context, bk, borrow) ) in reservation_warnings {
269+ let mut initial_diag = mbcx. report_conflicting_borrow ( context, ( & place, span) , bk, & borrow) ;
270+
271+ let lint_root = if let ClearCrossCrate :: Set ( ref vsi) = mbcx. mir . source_scope_local_data {
272+ let scope = mbcx. mir . source_info ( context. loc ) . scope ;
273+ vsi[ scope] . lint_root
274+ } else {
275+ id
276+ } ;
277+
278+ // Span and message don't matter; we overwrite them below anyway
279+ let mut diag = mbcx. infcx . tcx . struct_span_lint_hir (
280+ MUTABLE_BORROW_RESERVATION_CONFLICT , lint_root, DUMMY_SP , "" ) ;
281+
282+ diag. message = initial_diag. styled_message ( ) . clone ( ) ;
283+ diag. span = initial_diag. span . clone ( ) ;
284+
285+ initial_diag. cancel ( ) ;
286+ diag. buffer ( & mut mbcx. errors_buffer ) ;
287+ }
288+
263289 // For each non-user used mutable variable, check if it's been assigned from
264290 // a user-declared local. If so, then put that local into the used_mut set.
265291 // Note that this set is expected to be small - only upvars from closures
@@ -341,18 +367,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
341367 // if AST-borrowck signalled no errors, then
342368 // downgrade all the buffered MIR-borrowck errors
343369 // to warnings.
344- for err in & mut mbcx. errors_buffer {
345- if err. is_error ( ) {
346- err. level = Level :: Warning ;
347- err. warn (
348- "this error has been downgraded to a warning for backwards \
349- compatibility with previous releases",
350- ) ;
351- err. warn (
352- "this represents potential undefined behavior in your code and \
353- this warning will become a hard error in the future",
354- ) ;
355- }
370+
371+ for err in mbcx. errors_buffer . iter_mut ( ) {
372+ downgrade_if_error ( err) ;
356373 }
357374 }
358375 SignalledError :: SawSomeError => {
@@ -378,6 +395,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
378395 result
379396}
380397
398+ fn downgrade_if_error ( diag : & mut Diagnostic ) {
399+ if diag. is_error ( ) {
400+ diag. level = Level :: Warning ;
401+ diag. warn (
402+ "this error has been downgraded to a warning for backwards \
403+ compatibility with previous releases",
404+ ) ;
405+ diag. warn (
406+ "this represents potential undefined behavior in your code and \
407+ this warning will become a hard error in the future",
408+ ) ;
409+ }
410+ }
411+
381412pub struct MirBorrowckCtxt < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
382413 infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
383414 mir : & ' cx Mir < ' tcx > ,
@@ -410,6 +441,13 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
410441 // but it is currently inconvenient to track down the `BorrowIndex`
411442 // at the time we detect and report a reservation error.
412443 reservation_error_reported : FxHashSet < Place < ' tcx > > ,
444+ /// Migration warnings to be reported for #56254. We delay reporting these
445+ /// so that we can suppress the warning if there's a corresponding error
446+ /// for the activation of the borrow.
447+ reservation_warnings : FxHashMap <
448+ BorrowIndex ,
449+ ( Place < ' tcx > , Span , Context , BorrowKind , BorrowData < ' tcx > )
450+ > ,
413451 /// This field keeps track of move errors that are to be reported for given move indicies.
414452 ///
415453 /// There are situations where many errors can be reported for a single move out (see #53807)
@@ -921,11 +959,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
921959 let conflict_error =
922960 self . check_access_for_conflict ( context, place_span, sd, rw, flow_state) ;
923961
962+ if let ( Activation ( _, borrow_idx) , true ) = ( kind. 1 , conflict_error) {
963+ // Suppress this warning when there's an error being emited for the
964+ // same borrow: fixing the error is likely to fix the warning.
965+ self . reservation_warnings . remove ( & borrow_idx) ;
966+ }
967+
924968 if conflict_error || mutability_error {
925969 debug ! (
926970 "access_place: logging error place_span=`{:?}` kind=`{:?}`" ,
927971 place_span, kind
928972 ) ;
973+
929974 self . access_place_error_reported
930975 . insert ( ( place_span. 0 . clone ( ) , place_span. 1 ) ) ;
931976 }
@@ -976,8 +1021,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
9761021 Control :: Continue
9771022 }
9781023
979- ( Read ( _) , BorrowKind :: Shared ) | ( Reservation ( .. ) , BorrowKind :: Shared )
980- | ( Read ( _) , BorrowKind :: Shallow ) | ( Reservation ( .. ) , BorrowKind :: Shallow )
1024+ ( Read ( _) , BorrowKind :: Shared )
1025+ | ( Read ( _) , BorrowKind :: Shallow )
9811026 | ( Read ( ReadKind :: Borrow ( BorrowKind :: Shallow ) ) , BorrowKind :: Unique )
9821027 | ( Read ( ReadKind :: Borrow ( BorrowKind :: Shallow ) ) , BorrowKind :: Mut { .. } ) => {
9831028 Control :: Continue
@@ -991,28 +1036,53 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
9911036 ( Read ( kind) , BorrowKind :: Unique ) | ( Read ( kind) , BorrowKind :: Mut { .. } ) => {
9921037 // Reading from mere reservations of mutable-borrows is OK.
9931038 if !is_active ( & this. dominators , borrow, context. loc ) {
994- assert ! ( allow_two_phase_borrow( & this . infcx . tcx, borrow. kind) ) ;
1039+ assert ! ( allow_two_phase_borrow( & tcx, borrow. kind) ) ;
9951040 return Control :: Continue ;
9961041 }
9971042
9981043 error_reported = true ;
9991044 match kind {
10001045 ReadKind :: Copy => {
10011046 this. report_use_while_mutably_borrowed ( context, place_span, borrow)
1047+ . buffer ( & mut this. errors_buffer ) ;
10021048 }
10031049 ReadKind :: Borrow ( bk) => {
1004- this. report_conflicting_borrow ( context, place_span, bk, & borrow)
1050+ this. report_conflicting_borrow ( context, place_span, bk, borrow)
1051+ . buffer ( & mut this. errors_buffer ) ;
10051052 }
10061053 }
10071054 Control :: Break
10081055 }
10091056
1010- ( Reservation ( kind) , BorrowKind :: Unique )
1011- | ( Reservation ( kind) , BorrowKind :: Mut { .. } )
1057+ ( Reservation ( WriteKind :: MutableBorrow ( bk) ) , BorrowKind :: Shallow )
1058+ | ( Reservation ( WriteKind :: MutableBorrow ( bk) ) , BorrowKind :: Shared ) if {
1059+ tcx. migrate_borrowck ( )
1060+ } => {
1061+ let bi = this. borrow_set . location_map [ & context. loc ] ;
1062+ debug ! (
1063+ "recording invalid reservation of place: {:?} with \
1064+ borrow index {:?} as warning",
1065+ place_span. 0 ,
1066+ bi,
1067+ ) ;
1068+ // rust-lang/rust#56254 - This was previously permitted on
1069+ // the 2018 edition so we emit it as a warning. We buffer
1070+ // these sepately so that we only emit a warning if borrow
1071+ // checking was otherwise successful.
1072+ this. reservation_warnings . insert (
1073+ bi,
1074+ ( place_span. 0 . clone ( ) , place_span. 1 , context, bk, borrow. clone ( ) ) ,
1075+ ) ;
1076+
1077+ // Don't suppress actual errors.
1078+ Control :: Continue
1079+ }
1080+
1081+ ( Reservation ( kind) , _)
10121082 | ( Activation ( kind, _) , _)
10131083 | ( Write ( kind) , _) => {
10141084 match rw {
1015- Reservation ( _ ) => {
1085+ Reservation ( .. ) => {
10161086 debug ! (
10171087 "recording invalid reservation of \
10181088 place: {:?}",
@@ -1033,7 +1103,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10331103 error_reported = true ;
10341104 match kind {
10351105 WriteKind :: MutableBorrow ( bk) => {
1036- this. report_conflicting_borrow ( context, place_span, bk, & borrow)
1106+ this. report_conflicting_borrow ( context, place_span, bk, borrow)
1107+ . buffer ( & mut this. errors_buffer ) ;
10371108 }
10381109 WriteKind :: StorageDeadOrDrop => {
10391110 this. report_borrowed_value_does_not_live_long_enough (
@@ -1046,7 +1117,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10461117 this. report_illegal_mutation_of_borrowed ( context, place_span, borrow)
10471118 }
10481119 WriteKind :: Move => {
1049- this. report_move_out_while_borrowed ( context, place_span, & borrow)
1120+ this. report_move_out_while_borrowed ( context, place_span, borrow)
10501121 }
10511122 }
10521123 Control :: Break
0 commit comments