|
10 | 10 |
|
11 | 11 | //! This query borrow-checks the MIR to (further) ensure it is not broken.
|
12 | 12 |
|
| 13 | +use rustc::hir; |
13 | 14 | use rustc::hir::def_id::{DefId};
|
14 | 15 | use rustc::infer::{InferCtxt};
|
15 | 16 | use rustc::ty::{self, TyCtxt, ParamEnv};
|
@@ -447,9 +448,12 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
447 | 448 | lvalue_span: (&Lvalue<'tcx>, Span),
|
448 | 449 | kind: (ShallowOrDeep, ReadOrWrite),
|
449 | 450 | flow_state: &InProgress<'b, 'gcx, 'tcx>) {
|
450 |
| - // FIXME: also need to check permissions (e.g. reject mut |
451 |
| - // borrow of immutable ref, moves through non-`Box`-ref) |
| 451 | + |
452 | 452 | let (sd, rw) = kind;
|
| 453 | + |
| 454 | + // Check permissions |
| 455 | + self.check_access_permissions(lvalue_span, rw); |
| 456 | + |
453 | 457 | self.each_borrow_involving_path(
|
454 | 458 | context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
|
455 | 459 | match (rw, borrow.kind) {
|
@@ -861,6 +865,154 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
861 | 865 | }
|
862 | 866 | }
|
863 | 867 | }
|
| 868 | + |
| 869 | + /// Check the permissions for the given lvalue and read or write kind |
| 870 | + fn check_access_permissions(&self, (lvalue, span): (&Lvalue<'tcx>, Span), kind: ReadOrWrite) { |
| 871 | + match kind { |
| 872 | + Write(WriteKind::MutableBorrow(BorrowKind::Unique)) => { |
| 873 | + if let Err(_lvalue_err) = self.is_unique(lvalue) { |
| 874 | + span_bug!(span, "&unique borrow for `{}` should not fail", |
| 875 | + self.describe_lvalue(lvalue)); |
| 876 | + } |
| 877 | + }, |
| 878 | + Write(WriteKind::MutableBorrow(BorrowKind::Mut)) => { |
| 879 | + if let Err(lvalue_err) = self.is_mutable(lvalue) { |
| 880 | + let mut err = self.tcx.cannot_borrow_path_as_mutable(span, |
| 881 | + &format!("immutable item `{}`", |
| 882 | + self.describe_lvalue(lvalue)), |
| 883 | + Origin::Mir); |
| 884 | + err.span_label(span, "cannot borrow as mutable"); |
| 885 | + |
| 886 | + if lvalue != lvalue_err { |
| 887 | + err.note(&format!("Value not mutable causing this error: `{}`", |
| 888 | + self.describe_lvalue(lvalue_err))); |
| 889 | + } |
| 890 | + |
| 891 | + err.emit(); |
| 892 | + } |
| 893 | + }, |
| 894 | + _ => {}// Access authorized |
| 895 | + } |
| 896 | + } |
| 897 | + |
| 898 | + /// Can this value be written or borrowed mutably |
| 899 | + fn is_mutable<'d>(&self, lvalue: &'d Lvalue<'tcx>) -> Result<(), &'d Lvalue<'tcx>> { |
| 900 | + match *lvalue { |
| 901 | + Lvalue::Local(local) => { |
| 902 | + let local = &self.mir.local_decls[local]; |
| 903 | + match local.mutability { |
| 904 | + Mutability::Not => Err(lvalue), |
| 905 | + Mutability::Mut => Ok(()) |
| 906 | + } |
| 907 | + }, |
| 908 | + Lvalue::Static(ref static_) => { |
| 909 | + if !self.tcx.is_static_mut(static_.def_id) { |
| 910 | + Err(lvalue) |
| 911 | + } else { |
| 912 | + Ok(()) |
| 913 | + } |
| 914 | + }, |
| 915 | + Lvalue::Projection(ref proj) => { |
| 916 | + match proj.elem { |
| 917 | + ProjectionElem::Deref => { |
| 918 | + let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); |
| 919 | + |
| 920 | + // `Box<T>` owns its content, so mutable if its location is mutable |
| 921 | + if base_ty.is_box() { |
| 922 | + return self.is_mutable(&proj.base); |
| 923 | + } |
| 924 | + |
| 925 | + // Otherwise we check the kind of deref to decide |
| 926 | + match base_ty.sty { |
| 927 | + ty::TyRef(_, tnm) => { |
| 928 | + match tnm.mutbl { |
| 929 | + // Shared borrowed data is never mutable |
| 930 | + hir::MutImmutable => Err(lvalue), |
| 931 | + // Mutably borrowed data is mutable, but only if we have a |
| 932 | + // unique path to the `&mut` |
| 933 | + hir::MutMutable => self.is_unique(&proj.base), |
| 934 | + } |
| 935 | + }, |
| 936 | + ty::TyRawPtr(tnm) => { |
| 937 | + match tnm.mutbl { |
| 938 | + // `*const` raw pointers are not mutable |
| 939 | + hir::MutImmutable => Err(lvalue), |
| 940 | + // `*mut` raw pointers are always mutable, regardless of context |
| 941 | + // The users have to check by themselve. |
| 942 | + hir::MutMutable => Ok(()), |
| 943 | + } |
| 944 | + }, |
| 945 | + // Deref should only be for reference, pointers or boxes |
| 946 | + _ => bug!("Deref of unexpected type: {:?}", base_ty) |
| 947 | + } |
| 948 | + }, |
| 949 | + // All other projections are owned by their base path, so mutable if |
| 950 | + // base path is mutable |
| 951 | + ProjectionElem::Field(..) | |
| 952 | + ProjectionElem::Index(..) | |
| 953 | + ProjectionElem::ConstantIndex{..} | |
| 954 | + ProjectionElem::Subslice{..} | |
| 955 | + ProjectionElem::Downcast(..) => |
| 956 | + self.is_mutable(&proj.base) |
| 957 | + } |
| 958 | + } |
| 959 | + } |
| 960 | + } |
| 961 | + |
| 962 | + /// Does this lvalue have a unique path |
| 963 | + fn is_unique<'d>(&self, lvalue: &'d Lvalue<'tcx>) -> Result<(), &'d Lvalue<'tcx>> { |
| 964 | + match *lvalue { |
| 965 | + Lvalue::Local(..) => { |
| 966 | + // Local variables are unique |
| 967 | + Ok(()) |
| 968 | + }, |
| 969 | + Lvalue::Static(..) => { |
| 970 | + // Static variables are not |
| 971 | + Err(lvalue) |
| 972 | + }, |
| 973 | + Lvalue::Projection(ref proj) => { |
| 974 | + match proj.elem { |
| 975 | + ProjectionElem::Deref => { |
| 976 | + let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); |
| 977 | + |
| 978 | + // `Box<T>` referent is unique if box is a unique spot |
| 979 | + if base_ty.is_box() { |
| 980 | + return self.is_unique(&proj.base); |
| 981 | + } |
| 982 | + |
| 983 | + // Otherwise we check the kind of deref to decide |
| 984 | + match base_ty.sty { |
| 985 | + ty::TyRef(_, tnm) => { |
| 986 | + match tnm.mutbl { |
| 987 | + // lvalue represent an aliased location |
| 988 | + hir::MutImmutable => Err(lvalue), |
| 989 | + // `&mut T` is as unique as the context in which it is found |
| 990 | + hir::MutMutable => self.is_unique(&proj.base), |
| 991 | + } |
| 992 | + }, |
| 993 | + ty::TyRawPtr(tnm) => { |
| 994 | + match tnm.mutbl { |
| 995 | + // `*mut` can be aliased, but we leave it to user |
| 996 | + hir::MutMutable => Ok(()), |
| 997 | + // `*const` is treated the same as `*mut` |
| 998 | + hir::MutImmutable => Ok(()), |
| 999 | + } |
| 1000 | + }, |
| 1001 | + // Deref should only be for reference, pointers or boxes |
| 1002 | + _ => bug!("Deref of unexpected type: {:?}", base_ty) |
| 1003 | + } |
| 1004 | + }, |
| 1005 | + // Other projections are unique if the base is unique |
| 1006 | + ProjectionElem::Field(..) | |
| 1007 | + ProjectionElem::Index(..) | |
| 1008 | + ProjectionElem::ConstantIndex{..} | |
| 1009 | + ProjectionElem::Subslice{..} | |
| 1010 | + ProjectionElem::Downcast(..) => |
| 1011 | + self.is_unique(&proj.base) |
| 1012 | + } |
| 1013 | + } |
| 1014 | + } |
| 1015 | + } |
864 | 1016 | }
|
865 | 1017 |
|
866 | 1018 | #[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
0 commit comments