Auto merge of #1952 - RalfJung:self-referential, r=RalfJung

exclude mutable references to !Unpin types from uniqueness guarantees

This basically works around https://github.com/rust-lang/unsafe-code-guidelines/issues/148 by not requiring uniqueness any more for mutable references to self-referential generators. That corresponds to [the same work-around that was applied in rustc itself](b815532674/compiler/rustc_middle/src/ty/layout.rs (L2482)).

I am not entirely sure if this is a good idea since it might hide too many errors in case types are "accidentally" `!Unpin`. OTOH, our test suite still passes, and to my knowledge the vast majority of types is `Unpin`. (`place.layout.ty` is monomorphic, we should always exactly know which type this is.)
This commit is contained in:
bors 2022-01-09 14:10:00 +00:00
commit deb9bfd246
2 changed files with 49 additions and 3 deletions

View File

@ -9,7 +9,11 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_middle::mir::RetagKind; use rustc_middle::mir::RetagKind;
use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_middle::ty::{
self,
layout::{HasParamEnv, LayoutOf},
};
use rustc_span::DUMMY_SP;
use rustc_target::abi::Size; use rustc_target::abi::Size;
use crate::*; use crate::*;
@ -657,8 +661,16 @@ fn reborrow(
// Make sure that raw pointers and mutable shared references are reborrowed "weak": // Make sure that raw pointers and mutable shared references are reborrowed "weak":
// There could be existing unique pointers reborrowed from them that should remain valid! // There could be existing unique pointers reborrowed from them that should remain valid!
let perm = match kind { let perm = match kind {
RefKind::Unique { two_phase: false } => Permission::Unique, RefKind::Unique { two_phase: false }
RefKind::Unique { two_phase: true } => Permission::SharedReadWrite, if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
{
// Only if the type is unpin do we actually enforce uniqueness
Permission::Unique
}
RefKind::Unique { .. } => {
// Two-phase references and !Unpin references are treated as SharedReadWrite
Permission::SharedReadWrite
}
RefKind::Raw { mutable: true } => Permission::SharedReadWrite, RefKind::Raw { mutable: true } => Permission::SharedReadWrite,
RefKind::Shared | RefKind::Raw { mutable: false } => { RefKind::Shared | RefKind::Raw { mutable: false } => {
// Shared references and *const are a whole different kind of game, the // Shared references and *const are a whole different kind of game, the

View File

@ -0,0 +1,34 @@
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148:
// this fails when Stacked Borrows is strictly applied even to `!Unpin` types.
#![feature(generators, generator_trait)]
use std::{
ops::{Generator, GeneratorState},
pin::Pin,
};
fn firstn() -> impl Generator<Yield = u64, Return = ()> {
static move || {
let mut num = 0;
let num = &mut num;
yield *num;
*num += 1; //~ ERROR: borrow stack
yield *num;
*num += 1;
yield *num;
*num += 1;
}
}
fn main() {
let mut generator_iterator = firstn();
let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) };
let mut sum = 0;
while let GeneratorState::Yielded(x) = pin.as_mut().resume(()) {
sum += x;
}
assert_eq!(sum, 3);
}