Skip to content

Commit

Permalink
exclude mutable references to !Unpin types from uniqueness guarantees
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jan 1, 2022
1 parent d307e6c commit 77cec81
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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 77cec81

Please sign in to comment.