diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2919ce919a..37ecb749a4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -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::*; @@ -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 diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/run-pass/stacked-borrows/generators-self-referential.rs new file mode 100644 index 0000000000..01ce8a6141 --- /dev/null +++ b/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 { + 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); +}