@@ -6,6 +6,7 @@ use rustc::hir::Node;
6
6
use rustc:: hir:: def_id:: DefId ;
7
7
use rustc:: infer:: InferCtxt ;
8
8
use rustc:: lint:: builtin:: UNUSED_MUT ;
9
+ use rustc:: lint:: builtin:: { MUTABLE_BORROW_RESERVATION_CONFLICT } ;
9
10
use rustc:: middle:: borrowck:: SignalledError ;
10
11
use rustc:: mir:: { AggregateKind , BasicBlock , BorrowCheckResult , BorrowKind } ;
11
12
use rustc:: mir:: {
@@ -18,14 +19,15 @@ use rustc::ty::{self, TyCtxt};
18
19
19
20
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , Level } ;
20
21
use rustc_data_structures:: bit_set:: BitSet ;
21
- use rustc_data_structures:: fx:: FxHashSet ;
22
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
22
23
use rustc_data_structures:: graph:: dominators:: Dominators ;
23
24
use smallvec:: SmallVec ;
24
25
25
- use std:: rc:: Rc ;
26
26
use std:: collections:: BTreeMap ;
27
+ use std:: mem;
28
+ use std:: rc:: Rc ;
27
29
28
- use syntax_pos:: Span ;
30
+ use syntax_pos:: { Span , DUMMY_SP } ;
29
31
30
32
use crate :: dataflow:: indexes:: { BorrowIndex , InitIndex , MoveOutIndex , MovePathIndex } ;
31
33
use crate :: dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MoveError } ;
@@ -238,6 +240,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
238
240
locals_are_invalidated_at_exit,
239
241
access_place_error_reported : Default :: default ( ) ,
240
242
reservation_error_reported : Default :: default ( ) ,
243
+ reservation_warnings : Default :: default ( ) ,
241
244
move_error_reported : BTreeMap :: new ( ) ,
242
245
uninitialized_error_reported : Default :: default ( ) ,
243
246
errors_buffer,
@@ -260,6 +263,29 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
260
263
}
261
264
mbcx. analyze_results ( & mut state) ; // entry point for DataflowResultsConsumer
262
265
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
+
263
289
// For each non-user used mutable variable, check if it's been assigned from
264
290
// a user-declared local. If so, then put that local into the used_mut set.
265
291
// Note that this set is expected to be small - only upvars from closures
@@ -341,18 +367,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
341
367
// if AST-borrowck signalled no errors, then
342
368
// downgrade all the buffered MIR-borrowck errors
343
369
// 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) ;
356
373
}
357
374
}
358
375
SignalledError :: SawSomeError => {
@@ -378,6 +395,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
378
395
result
379
396
}
380
397
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
+
381
412
pub struct MirBorrowckCtxt < ' cx , ' gcx : ' tcx , ' tcx : ' cx > {
382
413
infcx : & ' cx InferCtxt < ' cx , ' gcx , ' tcx > ,
383
414
mir : & ' cx Mir < ' tcx > ,
@@ -410,6 +441,13 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
410
441
// but it is currently inconvenient to track down the `BorrowIndex`
411
442
// at the time we detect and report a reservation error.
412
443
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
+ > ,
413
451
/// This field keeps track of move errors that are to be reported for given move indicies.
414
452
///
415
453
/// 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> {
921
959
let conflict_error =
922
960
self . check_access_for_conflict ( context, place_span, sd, rw, flow_state) ;
923
961
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
+
924
968
if conflict_error || mutability_error {
925
969
debug ! (
926
970
"access_place: logging error place_span=`{:?}` kind=`{:?}`" ,
927
971
place_span, kind
928
972
) ;
973
+
929
974
self . access_place_error_reported
930
975
. insert ( ( place_span. 0 . clone ( ) , place_span. 1 ) ) ;
931
976
}
@@ -976,8 +1021,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
976
1021
Control :: Continue
977
1022
}
978
1023
979
- ( Read ( _) , BorrowKind :: Shared ) | ( Reservation ( .. ) , BorrowKind :: Shared )
980
- | ( Read ( _) , BorrowKind :: Shallow ) | ( Reservation ( .. ) , BorrowKind :: Shallow )
1024
+ ( Read ( _) , BorrowKind :: Shared )
1025
+ | ( Read ( _) , BorrowKind :: Shallow )
981
1026
| ( Read ( ReadKind :: Borrow ( BorrowKind :: Shallow ) ) , BorrowKind :: Unique )
982
1027
| ( Read ( ReadKind :: Borrow ( BorrowKind :: Shallow ) ) , BorrowKind :: Mut { .. } ) => {
983
1028
Control :: Continue
@@ -991,28 +1036,53 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
991
1036
( Read ( kind) , BorrowKind :: Unique ) | ( Read ( kind) , BorrowKind :: Mut { .. } ) => {
992
1037
// Reading from mere reservations of mutable-borrows is OK.
993
1038
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) ) ;
995
1040
return Control :: Continue ;
996
1041
}
997
1042
998
1043
error_reported = true ;
999
1044
match kind {
1000
1045
ReadKind :: Copy => {
1001
1046
this. report_use_while_mutably_borrowed ( context, place_span, borrow)
1047
+ . buffer ( & mut this. errors_buffer ) ;
1002
1048
}
1003
1049
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 ) ;
1005
1052
}
1006
1053
}
1007
1054
Control :: Break
1008
1055
}
1009
1056
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) , _)
1012
1082
| ( Activation ( kind, _) , _)
1013
1083
| ( Write ( kind) , _) => {
1014
1084
match rw {
1015
- Reservation ( _ ) => {
1085
+ Reservation ( .. ) => {
1016
1086
debug ! (
1017
1087
"recording invalid reservation of \
1018
1088
place: {:?}",
@@ -1033,7 +1103,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1033
1103
error_reported = true ;
1034
1104
match kind {
1035
1105
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 ) ;
1037
1108
}
1038
1109
WriteKind :: StorageDeadOrDrop => {
1039
1110
this. report_borrowed_value_does_not_live_long_enough (
@@ -1046,7 +1117,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1046
1117
this. report_illegal_mutation_of_borrowed ( context, place_span, borrow)
1047
1118
}
1048
1119
WriteKind :: Move => {
1049
- this. report_move_out_while_borrowed ( context, place_span, & borrow)
1120
+ this. report_move_out_while_borrowed ( context, place_span, borrow)
1050
1121
}
1051
1122
}
1052
1123
Control :: Break
0 commit comments