Skip to content

Commit

Permalink
Auto merge of #1952 - RalfJung:self-referential, r=RalfJung
Browse files Browse the repository at this point in the history
exclude mutable references to !Unpin types from uniqueness guarantees

This basically works around rust-lang/unsafe-code-guidelines#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](https://github.com/rust-lang/rust/blob/b81553267437627af63c79c1a20c73af865a842a/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.)
  • Loading branch information
bors committed Jan 9, 2022
2 parents c8b3cf0 + 77cec81 commit deb9bfd
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
18 changes: 15 additions & 3 deletions src/stacked_borrows.rs
Expand Up @@ -9,7 +9,11 @@ use std::num::NonZeroU64;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::Mutability;
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 crate::*;
Expand Down Expand Up @@ -657,8 +661,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// 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!
let perm = match kind {
RefKind::Unique { two_phase: false } => Permission::Unique,
RefKind::Unique { two_phase: true } => Permission::SharedReadWrite,
RefKind::Unique { two_phase: false }
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::Shared | RefKind::Raw { mutable: false } => {
// Shared references and *const are a whole different kind of game, the
Expand Down
34 changes: 34 additions & 0 deletions tests/run-pass/stacked-borrows/generators-self-referential.rs
@@ -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);
}

0 comments on commit deb9bfd

Please sign in to comment.