+ /// Add the constraints that arise from a borrow expression `&'a P` at the location `L`.
+ ///
+ /// # Parameters
+ ///
+ /// - `location`: the location `L` where the borrow expression occurs
+ /// - `borrow_region`: the region `'a` associated with the borrow
+ /// - `borrowed_place`: the place `P` being borrowed
+ fn add_reborrow_constraint(
+ &mut self,
+ location: Location,
+ borrow_region: ty::Region<'tcx>,
+ borrowed_place: &Place<'tcx>,
+ ) {
+ // These constraints are only meaningful during borrowck:
+ let BorrowCheckContext {
+ borrow_set,
+ location_table,
+ all_facts,
+ ..
+ } = match &mut self.borrowck_context {
+ Some(borrowck_context) => borrowck_context,
+ None => return,
+ };
+
+ // In Polonius mode, we also push a `borrow_region` fact
+ // linking the loan to the region (in some cases, though,
+ // there is no loan associated with this borrow expression --
+ // that occurs when we are borrowing an unsafe place, for
+ // example).
+ if let Some(all_facts) = all_facts {
+ if let Some(borrow_index) = borrow_set.location_map.get(&location) {
+ let region_vid = borrow_region.to_region_vid();
+ all_facts.borrow_region.push((
+ region_vid,
+ *borrow_index,
+ location_table.mid_index(location),
+ ));
+ }
+ }
+
+ // If we are reborrowing the referent of another reference, we
+ // need to add outlives relationships. In a case like `&mut
+ // *p`, where the `p` has type `&'b mut Foo`, for example, we
+ // need to ensure that `'b: 'a`.
+
+ let mut borrowed_place = borrowed_place;
+
+ debug!(
+ "add_reborrow_constraint({:?}, {:?}, {:?})",
+ location, borrow_region, borrowed_place
+ );
+ while let Place::Projection(box PlaceProjection { base, elem }) = borrowed_place {
+ debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
+
+ match *elem {
+ ProjectionElem::Deref => {
+ let tcx = self.infcx.tcx;
+ let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
+
+ debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
+ match base_ty.sty {
+ ty::TyRef(ref_region, _, mutbl) => {
+ self.constraints
+ .outlives_constraints
+ .push(OutlivesConstraint {
+ sup: ref_region.to_region_vid(),
+ sub: borrow_region.to_region_vid(),
+ locations: location.boring(),
+ next: None,
+ });
+
+ if let Some(all_facts) = all_facts {
+ all_facts.outlives.push((
+ ref_region.to_region_vid(),
+ borrow_region.to_region_vid(),
+ location_table.mid_index(location),
+ ));
+ }
+
+ match mutbl {
+ hir::Mutability::MutImmutable => {
+ // Immutable reference. We don't need the base
+ // to be valid for the entire lifetime of
+ // the borrow.
+ break;
+ }
+ hir::Mutability::MutMutable => {
+ // Mutable reference. We *do* need the base
+ // to be valid, because after the base becomes
+ // invalid, someone else can use our mutable deref.
+
+ // This is in order to make the following function
+ // illegal:
+ // ```
+ // fn unsafe_deref<'a, 'b>(x: &'a &'b mut T) -> &'b mut T {
+ // &mut *x
+ // }
+ // ```
+ //
+ // As otherwise you could clone `&mut T` using the
+ // following function:
+ // ```
+ // fn bad(x: &mut T) -> (&mut T, &mut T) {
+ // let my_clone = unsafe_deref(&'a x);
+ // ENDREGION 'a;
+ // (my_clone, x)
+ // }
+ // ```
+ }
+ }
+ }
+ ty::TyRawPtr(..) => {
+ // deref of raw pointer, guaranteed to be valid
+ break;
+ }
+ ty::TyAdt(def, _) if def.is_box() => {
+ // deref of `Box`, need the base to be valid - propagate
+ }
+ _ => bug!("unexpected deref ty {:?} in {:?}", base_ty, borrowed_place),
+ }
+ }
+ ProjectionElem::Field(..)
+ | ProjectionElem::Downcast(..)
+ | ProjectionElem::Index(..)
+ | ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Subslice { .. } => {
+ // other field access
+ }
+ }
+
+ // The "propagate" case. We need to check that our base is valid
+ // for the borrow's lifetime.
+ borrowed_place = base;
+ }
+ }
+