@@ -271,6 +271,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
271
271
self . access_lvalue ( context,
272
272
( output, span) ,
273
273
( Deep , Read ( ReadKind :: Copy ) ) ,
274
+ LocalMutationIsAllowed :: No ,
274
275
flow_state) ;
275
276
self . check_if_path_is_moved ( context, InitializationRequiringAction :: Use ,
276
277
( output, span) , flow_state) ;
@@ -300,7 +301,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
300
301
StatementKind :: StorageDead ( local) => {
301
302
self . access_lvalue ( ContextKind :: StorageDead . new ( location) ,
302
303
( & Lvalue :: Local ( local) , span) ,
303
- ( Shallow ( None ) , Write ( WriteKind :: StorageDeadOrDrop ) ) , flow_state) ;
304
+ ( Shallow ( None ) , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
305
+ LocalMutationIsAllowed :: Yes ,
306
+ flow_state) ;
304
307
}
305
308
}
306
309
}
@@ -322,6 +325,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
322
325
self . access_lvalue ( ContextKind :: Drop . new ( loc) ,
323
326
( drop_lvalue, span) ,
324
327
( Deep , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
328
+ LocalMutationIsAllowed :: Yes ,
325
329
flow_state) ;
326
330
}
327
331
TerminatorKind :: DropAndReplace { location : ref drop_lvalue,
@@ -391,6 +395,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
391
395
ContextKind :: StorageDead . new ( loc) ,
392
396
( & root_lvalue, self . mir . source_info ( borrow. location ) . span ) ,
393
397
( Deep , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
398
+ LocalMutationIsAllowed :: Yes ,
394
399
flow_state
395
400
) ;
396
401
}
@@ -399,6 +404,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
399
404
ContextKind :: StorageDead . new ( loc) ,
400
405
( & root_lvalue, self . mir . source_info ( borrow. location ) . span ) ,
401
406
( Shallow ( None ) , Write ( WriteKind :: StorageDeadOrDrop ) ) ,
407
+ LocalMutationIsAllowed :: Yes ,
402
408
flow_state
403
409
) ;
404
410
}
@@ -445,6 +451,8 @@ enum ShallowOrDeep {
445
451
Deep ,
446
452
}
447
453
454
+ /// Kind of access to a value: read or write
455
+ /// (For informational purposes only)
448
456
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
449
457
enum ReadOrWrite {
450
458
/// From the RFC: "A *read* means that the existing data may be
@@ -457,12 +465,16 @@ enum ReadOrWrite {
457
465
Write ( WriteKind ) ,
458
466
}
459
467
468
+ /// Kind of read access to a value
469
+ /// (For informational purposes only)
460
470
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
461
471
enum ReadKind {
462
472
Borrow ( BorrowKind ) ,
463
473
Copy ,
464
474
}
465
475
476
+ /// Kind of write access to a value
477
+ /// (For informational purposes only)
466
478
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
467
479
enum WriteKind {
468
480
StorageDeadOrDrop ,
@@ -471,6 +483,20 @@ enum WriteKind {
471
483
Move ,
472
484
}
473
485
486
+ /// When checking permissions for an lvalue access, this flag is used to indicate that an immutable
487
+ /// local lvalue can be mutated.
488
+ ///
489
+ /// FIXME: @nikomatsakis suggested that this flag could be removed with the following modifications:
490
+ /// - Merge `check_access_permissions()` and `check_if_reassignment_to_immutable_state()`
491
+ /// - Split `is_mutable()` into `is_assignable()` (can be directly assigned) and
492
+ /// `is_declared_mutable()`
493
+ /// - Take flow state into consideration in `is_assignable()` for local variables
494
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
495
+ enum LocalMutationIsAllowed {
496
+ Yes ,
497
+ No
498
+ }
499
+
474
500
#[ derive( Copy , Clone ) ]
475
501
enum InitializationRequiringAction {
476
502
Update ,
@@ -510,6 +536,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
510
536
context : Context ,
511
537
lvalue_span : ( & Lvalue < ' tcx > , Span ) ,
512
538
kind : ( ShallowOrDeep , ReadOrWrite ) ,
539
+ is_local_mutation_allowed : LocalMutationIsAllowed ,
513
540
flow_state : & InProgress < ' cx , ' gcx , ' tcx > ) {
514
541
let ( sd, rw) = kind;
515
542
@@ -526,9 +553,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
526
553
}
527
554
528
555
// Check permissions
529
- self . check_access_permissions ( lvalue_span, rw) ;
556
+ let mut error_reported = self . check_access_permissions ( lvalue_span,
557
+ rw,
558
+ is_local_mutation_allowed) ;
530
559
531
- let mut error_reported = false ;
532
560
self . each_borrow_involving_path (
533
561
context, ( sd, lvalue_span. 0 ) , flow_state, |this, _index, borrow, common_prefix| {
534
562
match ( rw, borrow. kind ) {
@@ -614,7 +642,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
614
642
}
615
643
}
616
644
617
- self . access_lvalue ( context, lvalue_span, ( kind, Write ( WriteKind :: Mutate ) ) , flow_state) ;
645
+ self . access_lvalue ( context,
646
+ lvalue_span,
647
+ ( kind, Write ( WriteKind :: Mutate ) ) ,
648
+ LocalMutationIsAllowed :: Yes ,
649
+ flow_state) ;
618
650
619
651
// check for reassignments to immutable local variables
620
652
self . check_if_reassignment_to_immutable_state ( context, lvalue_span, flow_state) ;
@@ -632,7 +664,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
632
664
BorrowKind :: Unique |
633
665
BorrowKind :: Mut => ( Deep , Write ( WriteKind :: MutableBorrow ( bk) ) ) ,
634
666
} ;
635
- self . access_lvalue ( context, ( lvalue, span) , access_kind, flow_state) ;
667
+ self . access_lvalue ( context,
668
+ ( lvalue, span) ,
669
+ access_kind,
670
+ LocalMutationIsAllowed :: No ,
671
+ flow_state) ;
636
672
self . check_if_path_is_moved ( context, InitializationRequiringAction :: Borrow ,
637
673
( lvalue, span) , flow_state) ;
638
674
}
@@ -651,8 +687,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
651
687
Rvalue :: Discriminant ( ..) => ArtificialField :: Discriminant ,
652
688
_ => unreachable ! ( ) ,
653
689
} ;
654
- self . access_lvalue (
655
- context, ( lvalue, span) , ( Shallow ( Some ( af) ) , Read ( ReadKind :: Copy ) ) , flow_state) ;
690
+ self . access_lvalue ( context,
691
+ ( lvalue, span) ,
692
+ ( Shallow ( Some ( af) ) , Read ( ReadKind :: Copy ) ) ,
693
+ LocalMutationIsAllowed :: No ,
694
+ flow_state) ;
656
695
self . check_if_path_is_moved ( context, InitializationRequiringAction :: Use ,
657
696
( lvalue, span) , flow_state) ;
658
697
}
@@ -690,6 +729,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
690
729
self . access_lvalue ( context,
691
730
( lvalue, span) ,
692
731
( Deep , Read ( ReadKind :: Copy ) ) ,
732
+ LocalMutationIsAllowed :: No ,
693
733
flow_state) ;
694
734
695
735
// Finally, check if path was already moved.
@@ -701,6 +741,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
701
741
self . access_lvalue ( context,
702
742
( lvalue, span) ,
703
743
( Deep , Write ( WriteKind :: Move ) ) ,
744
+ LocalMutationIsAllowed :: Yes ,
704
745
flow_state) ;
705
746
706
747
// Finally, check if path was already moved.
@@ -735,9 +776,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
735
776
}
736
777
Lvalue :: Static ( ref static_) => {
737
778
// mutation of non-mut static is always illegal,
738
- // independent of dataflow.
779
+ // independent of dataflow. However it will be catched by
780
+ // `check_access_permissions()`, we call delay_span_bug here
781
+ // to be sure that no case has been missed
739
782
if !self . tcx . is_static_mut ( static_. def_id ) {
740
- self . report_assignment_to_static ( context, ( lvalue, span) ) ;
783
+ let item_msg = match self . describe_lvalue ( lvalue) {
784
+ Some ( name) => format ! ( "immutable static item `{}`" , name) ,
785
+ None => "immutable static item" . to_owned ( )
786
+ } ;
787
+ self . tcx . sess . delay_span_bug ( span,
788
+ & format ! ( "cannot assign to {}, should have been caught by \
789
+ `check_access_permissions()`", item_msg) ) ;
741
790
}
742
791
return ;
743
792
}
@@ -949,41 +998,101 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
949
998
}
950
999
951
1000
/// Check the permissions for the given lvalue and read or write kind
952
- fn check_access_permissions ( & self , ( lvalue, span) : ( & Lvalue < ' tcx > , Span ) , kind : ReadOrWrite ) {
1001
+ ///
1002
+ /// Returns true if an error is reported, false otherwise.
1003
+ fn check_access_permissions ( & self ,
1004
+ ( lvalue, span) : ( & Lvalue < ' tcx > , Span ) ,
1005
+ kind : ReadOrWrite ,
1006
+ is_local_mutation_allowed : LocalMutationIsAllowed )
1007
+ -> bool {
1008
+ debug ! ( "check_access_permissions({:?}, {:?}, {:?})" ,
1009
+ lvalue, kind, is_local_mutation_allowed) ;
1010
+ let mut error_reported = false ;
953
1011
match kind {
954
1012
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Unique ) ) => {
955
1013
if let Err ( _lvalue_err) = self . is_unique ( lvalue) {
956
- span_bug ! ( span, "&unique borrow for `{}` should not fail" ,
957
- self . describe_lvalue( lvalue) ) ;
1014
+ span_bug ! ( span, "&unique borrow for {:?} should not fail" , lvalue) ;
958
1015
}
959
1016
} ,
960
1017
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Mut ) ) => {
961
- if let Err ( lvalue_err) = self . is_mutable ( lvalue) {
1018
+ if let Err ( lvalue_err) = self . is_mutable ( lvalue, is_local_mutation_allowed) {
1019
+ error_reported = true ;
1020
+
1021
+ let item_msg = match self . describe_lvalue ( lvalue) {
1022
+ Some ( name) => format ! ( "immutable item `{}`" , name) ,
1023
+ None => "immutable item" . to_owned ( )
1024
+ } ;
1025
+
962
1026
let mut err = self . tcx . cannot_borrow_path_as_mutable ( span,
963
- & format ! ( "immutable item `{}`" ,
964
- self . describe_lvalue( lvalue) ) ,
1027
+ & item_msg,
965
1028
Origin :: Mir ) ;
966
1029
err. span_label ( span, "cannot borrow as mutable" ) ;
967
1030
968
1031
if lvalue != lvalue_err {
969
- err. note ( & format ! ( "Value not mutable causing this error: `{}`" ,
970
- self . describe_lvalue( lvalue_err) ) ) ;
1032
+ if let Some ( name) = self . describe_lvalue ( lvalue_err) {
1033
+ err. note ( & format ! ( "Value not mutable causing this error: `{}`" , name) ) ;
1034
+ }
1035
+ }
1036
+
1037
+ err. emit ( ) ;
1038
+ }
1039
+ } ,
1040
+ Write ( WriteKind :: Mutate ) => {
1041
+ if let Err ( lvalue_err) = self . is_mutable ( lvalue, is_local_mutation_allowed) {
1042
+ error_reported = true ;
1043
+
1044
+ let item_msg = match self . describe_lvalue ( lvalue) {
1045
+ Some ( name) => format ! ( "immutable item `{}`" , name) ,
1046
+ None => "immutable item" . to_owned ( )
1047
+ } ;
1048
+
1049
+ let mut err = self . tcx . cannot_assign ( span,
1050
+ & item_msg,
1051
+ Origin :: Mir ) ;
1052
+ err. span_label ( span, "cannot mutate" ) ;
1053
+
1054
+ if lvalue != lvalue_err {
1055
+ if let Some ( name) = self . describe_lvalue ( lvalue_err) {
1056
+ err. note ( & format ! ( "Value not mutable causing this error: `{}`" , name) ) ;
1057
+ }
971
1058
}
972
1059
973
1060
err. emit ( ) ;
974
1061
}
975
1062
} ,
976
- _ => { } // Access authorized
1063
+ Write ( WriteKind :: Move ) |
1064
+ Write ( WriteKind :: StorageDeadOrDrop ) |
1065
+ Write ( WriteKind :: MutableBorrow ( BorrowKind :: Shared ) ) => {
1066
+ if let Err ( _lvalue_err) = self . is_mutable ( lvalue, is_local_mutation_allowed) {
1067
+ self . tcx . sess . delay_span_bug ( span,
1068
+ & format ! ( "Accessing `{:?}` with the kind `{:?}` shouldn't be possible" ,
1069
+ lvalue,
1070
+ kind) ) ;
1071
+ }
1072
+ } ,
1073
+ Read ( ReadKind :: Borrow ( BorrowKind :: Unique ) ) |
1074
+ Read ( ReadKind :: Borrow ( BorrowKind :: Mut ) ) |
1075
+ Read ( ReadKind :: Borrow ( BorrowKind :: Shared ) ) |
1076
+ Read ( ReadKind :: Copy ) => { } // Access authorized
977
1077
}
1078
+
1079
+ error_reported
978
1080
}
979
1081
980
1082
/// Can this value be written or borrowed mutably
981
- fn is_mutable < ' d > ( & self , lvalue : & ' d Lvalue < ' tcx > ) -> Result < ( ) , & ' d Lvalue < ' tcx > > {
1083
+ fn is_mutable < ' d > ( & self ,
1084
+ lvalue : & ' d Lvalue < ' tcx > ,
1085
+ is_local_mutation_allowed : LocalMutationIsAllowed )
1086
+ -> Result < ( ) , & ' d Lvalue < ' tcx > > {
982
1087
match * lvalue {
983
1088
Lvalue :: Local ( local) => {
984
1089
let local = & self . mir . local_decls [ local] ;
985
1090
match local. mutability {
986
- Mutability :: Not => Err ( lvalue) ,
1091
+ Mutability :: Not =>
1092
+ match is_local_mutation_allowed {
1093
+ LocalMutationIsAllowed :: Yes => Ok ( ( ) ) ,
1094
+ LocalMutationIsAllowed :: No => Err ( lvalue) ,
1095
+ } ,
987
1096
Mutability :: Mut => Ok ( ( ) )
988
1097
}
989
1098
} ,
@@ -1001,7 +1110,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1001
1110
1002
1111
// `Box<T>` owns its content, so mutable if its location is mutable
1003
1112
if base_ty. is_box ( ) {
1004
- return self . is_mutable ( & proj. base ) ;
1113
+ return self . is_mutable ( & proj. base , LocalMutationIsAllowed :: No ) ;
1005
1114
}
1006
1115
1007
1116
// Otherwise we check the kind of deref to decide
@@ -1035,7 +1144,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1035
1144
ProjectionElem :: ConstantIndex { ..} |
1036
1145
ProjectionElem :: Subslice { ..} |
1037
1146
ProjectionElem :: Downcast ( ..) =>
1038
- self . is_mutable ( & proj. base )
1147
+ self . is_mutable ( & proj. base , LocalMutationIsAllowed :: No )
1039
1148
}
1040
1149
}
1041
1150
}
@@ -1604,14 +1713,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1604
1713
}
1605
1714
err. emit ( ) ;
1606
1715
}
1607
-
1608
- fn report_assignment_to_static ( & mut self ,
1609
- _context : Context ,
1610
- ( lvalue, span) : ( & Lvalue < ' tcx > , Span ) ) {
1611
- let mut err = self . tcx . cannot_assign_static (
1612
- span, & self . describe_lvalue ( lvalue) , Origin :: Mir ) ;
1613
- err. emit ( ) ;
1614
- }
1615
1716
}
1616
1717
1617
1718
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
0 commit comments