From 77cec811b44ff5931251b5fcaf5594b63dae0afa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jan 2022 19:01:46 +0100 Subject: [PATCH] exclude mutable references to !Unpin types from uniqueness guarantees --- src/stacked_borrows.rs | 18 ++++++++-- .../generators-self-referential.rs | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/stacked-borrows/generators-self-referential.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2919ce919aa..37ecb749a48 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,7 +9,11 @@ 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 @@ fn reborrow( // 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 00000000000..01ce8a61418 --- /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); +}