Auto merge of #112070 - lcnr:disjoint-closure-capture-ub, r=oli-obk

change `BorrowKind::Unique` to be a mutating `PlaceContext`

fixes #112056

I believe that `BorrowKind::Unique` is a footgun in general, so I added a FIXME and opened https://github.com/rust-lang/rust/issues/112072. This is a bit too involved for this PR though.
This commit is contained in:
bors 2023-05-31 00:24:39 +00:00
commit e6e4f7ed15
14 changed files with 90 additions and 19 deletions

View File

@ -50,7 +50,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
// `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
// contain dangling references.

View File

@ -766,8 +766,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
PlaceContext::MutatingUse(_) => ty::Invariant,
PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
PlaceContext::NonMutatingUse(
Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | UniqueBorrow
| AddressOf | Projection,
Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf
| Projection,
) => ty::Covariant,
PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
}

View File

@ -234,7 +234,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
| PlaceContext::NonMutatingUse(
NonMutatingUseContext::Inspect
| NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::UniqueBorrow
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::AddressOf
| NonMutatingUseContext::Projection,

View File

@ -412,9 +412,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shallow => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
}
BorrowKind::Unique => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
}
BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow),
BorrowKind::Mut { .. } => {
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
}

View File

@ -220,6 +220,11 @@ pub enum BorrowKind {
/// immutable, but not aliasable. This solves the problem. For
/// simplicity, we don't give users the way to express this
/// borrow, it's just used when translating closures.
///
// FIXME(#112072): This is wrong. Unique borrows are mutable borrows except
// that they do not require their pointee to be marked as a mutable.
// They should still be treated as mutable borrows in every other way,
// e.g. for variance or overlap checking.
Unique,
/// Data is mutable and not aliasable.

View File

@ -650,8 +650,8 @@ macro_rules! make_mir_visitor {
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
NonMutatingUseContext::ShallowBorrow
),
BorrowKind::Unique => PlaceContext::NonMutatingUse(
NonMutatingUseContext::UniqueBorrow
BorrowKind::Unique => PlaceContext::MutatingUse(
MutatingUseContext::Borrow
),
BorrowKind::Mut { .. } =>
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
@ -1265,8 +1265,6 @@ pub enum NonMutatingUseContext {
SharedBorrow,
/// Shallow borrow.
ShallowBorrow,
/// Unique borrow.
UniqueBorrow,
/// AddressOf for *const pointer.
AddressOf,
/// PlaceMention statement.
@ -1345,9 +1343,7 @@ impl PlaceContext {
matches!(
self,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::UniqueBorrow
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
)
}

View File

@ -199,8 +199,7 @@ impl DefUse {
| NonMutatingUseContext::Move
| NonMutatingUseContext::PlaceMention
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::UniqueBorrow,
| NonMutatingUseContext::SharedBorrow,
) => Some(DefUse::Use),
PlaceContext::MutatingUse(MutatingUseContext::Projection)

View File

@ -772,7 +772,6 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
// mutation.
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
| NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
| NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
| NonMutatingUse(NonMutatingUseContext::AddressOf)
| MutatingUse(MutatingUseContext::Borrow)
| MutatingUse(MutatingUseContext::AddressOf) => {

View File

@ -130,7 +130,6 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::UniqueBorrow
| NonMutatingUseContext::AddressOf,
) => true,
// For debuginfo, merging locals is ok.

View File

@ -216,7 +216,6 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::UniqueBorrow
| NonMutatingUseContext::AddressOf,
)
| PlaceContext::MutatingUse(_) => {

View File

@ -0,0 +1,18 @@
// edition:2021
// regression test for #112056
fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) {
let mut closure = |input| x.0 = input;
//~^ ERROR: lifetime may not live long enough
closure(y);
}
fn main() {
let mut tuple = ("static",);
{
let x = String::from("temporary");
extend_lifetime(&mut tuple, &x);
}
println!("{}", tuple.0);
}

View File

@ -0,0 +1,14 @@
error: lifetime may not live long enough
--> $DIR/unique-borrows-are-invariant-1.rs:6:31
|
LL | fn extend_lifetime<'a, 'b>(x: &mut (&'a str,), y: &'b str) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
LL | let mut closure = |input| x.0 = input;
| ^^^^^^^^^^^ assignment requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
error: aborting due to previous error

View File

@ -0,0 +1,31 @@
// edition:2021
// regression test for #112056
struct Spooky<'b> {
owned: Option<&'static u32>,
borrowed: &'b &'static u32,
}
impl<'b> Spooky<'b> {
fn create_self_reference<'a>(&'a mut self) {
let mut closure = || {
if let Some(owned) = &self.owned {
let borrow: &'a &'static u32 = owned;
self.borrowed = borrow;
//~^ ERROR: lifetime may not live long enough
}
};
closure();
}
}
fn main() {
let mut spooky: Spooky<'static> = Spooky {
owned: Some(&1),
borrowed: &&1,
};
spooky.create_self_reference();
spooky.owned = None;
println!("{}", **spooky.borrowed);
}

View File

@ -0,0 +1,15 @@
error: lifetime may not live long enough
--> $DIR/unique-borrows-are-invariant-2.rs:15:17
|
LL | impl<'b> Spooky<'b> {
| -- lifetime `'b` defined here
LL | fn create_self_reference<'a>(&'a mut self) {
| -- lifetime `'a` defined here
...
LL | self.borrowed = borrow;
| ^^^^^^^^^^^^^^^^^^^^^^ assignment requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
error: aborting due to previous error