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:
commit
deb9bfd246
@ -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
|
||||||
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user