param_env: ty::ParamEnv<'tcx>,
}
+impl<'tcx> TransferFunction<'_, '_, 'tcx> {
+ /// Returns `true` if this borrow would allow mutation of the `borrowed_place`.
+ fn borrow_allows_mutation(
+ &self,
+ kind: mir::BorrowKind,
+ borrowed_place: &mir::Place<'tcx>,
+ ) -> bool {
+ let borrowed_ty = borrowed_place.ty(self.body, self.tcx).ty;
+
+ // Zero-sized types cannot be mutated, since there is nothing inside to mutate.
+ //
+ // FIXME: For now, we only exempt arrays of length zero. We need to carefully
+ // consider the effects before extending this to all ZSTs.
+ if let ty::Array(_, len) = borrowed_ty.kind {
+ if len.try_eval_usize(self.tcx, self.param_env) == Some(0) {
+ return false;
+ }
+ }
+
+ match kind {
+ mir::BorrowKind::Mut { .. } => true,
+
+ | mir::BorrowKind::Shared
+ | mir::BorrowKind::Shallow
+ | mir::BorrowKind::Unique
+ => !borrowed_ty.is_freeze(self.tcx, self.param_env, DUMMY_SP),
+ }
+ }
+}
+
impl<'tcx> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx> {
fn visit_rvalue(
&mut self,
location: Location,
) {
if let mir::Rvalue::Ref(_, kind, ref borrowed_place) = *rvalue {
- let is_mut = match kind {
- mir::BorrowKind::Mut { .. } => true,
-
- | mir::BorrowKind::Shared
- | mir::BorrowKind::Shallow
- | mir::BorrowKind::Unique
- => {
- !borrowed_place
- .ty(self.body, self.tcx)
- .ty
- .is_freeze(self.tcx, self.param_env, DUMMY_SP)
- }
- };
-
- if is_mut {
+ if self.borrow_allows_mutation(kind, borrowed_place) {
match borrowed_place.base {
mir::PlaceBase::Local(borrowed_local) if !borrowed_place.is_indirect()
=> self.trans.gen(borrowed_local),