/// new pointer.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
enum RefKind {
- /// `&mut` and `Box`.
+ /// `Box`.
+ Box,
+ /// `&mut`.
Unique { two_phase: bool },
/// `&` with or without interior mutability.
Shared,
impl fmt::Display for RefKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
+ RefKind::Box => write!(f, "Box"),
RefKind::Unique { two_phase: false } => write!(f, "unique reference"),
RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"),
RefKind::Shared => write!(f, "shared reference"),
let (perm, access) = match kind {
RefKind::Unique { two_phase } => {
// Permission is Unique only if the type is `Unpin` and this is not twophase
- let perm = if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
- Permission::Unique
+ if !two_phase && place.layout.ty.is_unpin(*this.tcx, this.param_env()) {
+ (Permission::Unique, Some(AccessKind::Write))
} else {
- Permission::SharedReadWrite
- };
- // We do an access for all full borrows, even if `!Unpin`.
- let access = if !two_phase { Some(AccessKind::Write) } else { None };
- (perm, access)
+ // FIXME: We emit `dereferenceable` for `!Unpin` mutable references, so we
+ // should do fake accesses here. But then we run into
+ // <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>, so for now
+ // we don't do that.
+ (Permission::SharedReadWrite, None)
+ }
}
+ RefKind::Box => (Permission::Unique, Some(AccessKind::Write)),
RefKind::Raw { mutable: true } => {
// Creating a raw ptr does not count as an access
(Permission::SharedReadWrite, None)
// Boxes get a weak protectors, since they may be deallocated.
self.retag_place(
place,
- RefKind::Unique { two_phase: false },
+ RefKind::Box,
self.retag_cause,
/*protector*/
(self.kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
+++ /dev/null
-//! Reborrowing a `&mut !Unpin` must still act like a (fake) read.
-use std::marker::PhantomPinned;
-
-struct NotUnpin(i32, PhantomPinned);
-
-fn main() {
- unsafe {
- let mut x = NotUnpin(0, PhantomPinned);
- // Mutable borrow of `Unpin` field (with lifetime laundering)
- let fieldref = &mut *(&mut x.0 as *mut i32);
- // Mutable reborrow of the entire `x`, which is `!Unpin` but should
- // still count as a read since we would add `dereferenceable`.
- let _xref = &mut x;
- // That read should have invalidated `fieldref`.
- *fieldref = 0; //~ ERROR: /write access .* tag does not exist in the borrow stack/
- }
-}
+++ /dev/null
-error: Undefined Behavior: attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | *fieldref = 0;
- | ^^^^^^^^^^^^^
- | |
- | attempting a write access using <TAG> at ALLOC[0x0], but that tag does not exist in the borrow stack for this location
- | this error occurs as part of an access at ALLOC[0x0..0x4]
- |
- = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
- = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
-help: <TAG> was created by a Unique retag at offsets [0x0..0x4]
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | let fieldref = &mut *(&mut x.0 as *mut i32);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: <TAG> was later invalidated at offsets [0x0..0x4] by a SharedReadWrite retag
- --> $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
- |
-LL | let _xref = &mut x;
- | ^^^^^^
- = note: BACKTRACE:
- = note: inside `main` at $DIR/notunpin_dereferenceable_fakeread.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to previous error
-