fix linking of place projections
projections other than dereferences of `&mut` used to do no linking. Fix that. Fixes #46974.
This commit is contained in:
parent
17d4e9be2a
commit
bd1bd76cd8
3 changed files with 120 additions and 19 deletions
|
@ -130,38 +130,91 @@ impl<'cx, 'cg, 'gcx, 'tcx> ConstraintGeneration<'cx, 'cg, 'gcx, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
// Add the reborrow constraint at `location` so that `borrowed_place`
|
||||
// is valid for `borrow_region`.
|
||||
fn add_reborrow_constraint(
|
||||
&mut self,
|
||||
location: Location,
|
||||
borrow_region: ty::Region<'tcx>,
|
||||
borrowed_place: &Place<'tcx>,
|
||||
) {
|
||||
if let Projection(ref proj) = *borrowed_place {
|
||||
let PlaceProjection { ref base, ref elem } = **proj;
|
||||
let mut borrowed_place = borrowed_place;
|
||||
|
||||
if let ProjectionElem::Deref = *elem {
|
||||
let tcx = self.infcx.tcx;
|
||||
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
|
||||
let base_sty = &base_ty.sty;
|
||||
debug!("add_reborrow_constraint({:?}, {:?}, {:?})",
|
||||
location, borrow_region, borrowed_place);
|
||||
while let Projection(box PlaceProjection { base, elem }) = borrowed_place {
|
||||
debug!("add_reborrow_constraint - iteration {:?}", borrowed_place);
|
||||
|
||||
if let ty::TyRef(base_region, ty::TypeAndMut { ty: _, mutbl }) = *base_sty {
|
||||
match mutbl {
|
||||
hir::Mutability::MutImmutable => {}
|
||||
match *elem {
|
||||
ProjectionElem::Deref => {
|
||||
let tcx = self.infcx.tcx;
|
||||
let base_ty = base.ty(self.mir, tcx).to_ty(tcx);
|
||||
|
||||
hir::Mutability::MutMutable => {
|
||||
self.add_reborrow_constraint(location, borrow_region, base);
|
||||
debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
|
||||
match base_ty.sty {
|
||||
ty::TyRef(ref_region, ty::TypeAndMut { ty: _, mutbl }) => {
|
||||
let span = self.mir.source_info(location).span;
|
||||
self.regioncx.add_outlives(
|
||||
span,
|
||||
ref_region.to_region_vid(),
|
||||
borrow_region.to_region_vid(),
|
||||
location.successor_within_block(),
|
||||
);
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
let span = self.mir.source_info(location).span;
|
||||
self.regioncx.add_outlives(
|
||||
span,
|
||||
base_region.to_region_vid(),
|
||||
borrow_region.to_region_vid(),
|
||||
location.successor_within_block(),
|
||||
);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
31
src/test/ui/nll/guarantor-issue-46974.rs
Normal file
31
src/test/ui/nll/guarantor-issue-46974.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that NLL analysis propagates lifetimes correctly through
|
||||
// field accesses, Box accesses, etc.
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
fn foo(s: &mut (i32,)) -> i32 {
|
||||
let t = &mut *s; // this borrow should last for the entire function
|
||||
let x = &t.0;
|
||||
*s = (2,); //~ ERROR cannot assign to `*s`
|
||||
*x
|
||||
}
|
||||
|
||||
fn bar(s: &Box<(i32,)>) -> &'static i32 {
|
||||
// FIXME(#46983): error message should be better
|
||||
&s.0 //~ ERROR free region `` does not outlive free region `'static`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo(&mut (0,));
|
||||
bar(&Box::new((1,)));
|
||||
}
|
17
src/test/ui/nll/guarantor-issue-46974.stderr
Normal file
17
src/test/ui/nll/guarantor-issue-46974.stderr
Normal file
|
@ -0,0 +1,17 @@
|
|||
error[E0506]: cannot assign to `*s` because it is borrowed
|
||||
--> $DIR/guarantor-issue-46974.rs:19:5
|
||||
|
|
||||
17 | let t = &mut *s; // this borrow should last for the entire function
|
||||
| ------- borrow of `*s` occurs here
|
||||
18 | let x = &t.0;
|
||||
19 | *s = (2,); //~ ERROR cannot assign to `*s`
|
||||
| ^^^^^^^^^ assignment to borrowed `*s` occurs here
|
||||
|
||||
error: free region `` does not outlive free region `'static`
|
||||
--> $DIR/guarantor-issue-46974.rs:25:5
|
||||
|
|
||||
25 | &s.0 //~ ERROR free region `` does not outlive free region `'static`
|
||||
| ^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Add table
Reference in a new issue