Merge pull request #4307 from JoJoDeveloping/remove-unique-is-unique

Remove -Zunique-is-unique
This commit is contained in:
Ralf Jung 2025-05-05 06:47:59 +00:00 committed by GitHub
commit f8a8bbd4c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 12 additions and 451 deletions

View file

@ -457,9 +457,6 @@ to Miri failing to detect cases of undefined behavior in a program.
casts are not supported in this mode, but that may change in the future.
* `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
`4` is default for most targets. This value should always be a power of 2 and nonzero.
* `-Zmiri-unique-is-unique` performs additional aliasing checks for `core::ptr::Unique` to ensure
that it could theoretically be considered `noalias`. This flag is experimental and has
an effect only when used with `-Zmiri-tree-borrows`.
[function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier

View file

@ -554,8 +554,6 @@ fn main() {
} else if arg == "-Zmiri-tree-borrows" {
miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows);
miri_config.provenance_mode = ProvenanceMode::Strict;
} else if arg == "-Zmiri-unique-is-unique" {
miri_config.unique_is_unique = true;
} else if arg == "-Zmiri-disable-data-race-detector" {
miri_config.data_race_detector = false;
miri_config.weak_memory_emulation = false;
@ -722,14 +720,6 @@ fn main() {
rustc_args.push(arg);
}
}
// `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows`.
if miri_config.unique_is_unique
&& !matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows))
{
show_error!(
"-Zmiri-unique-is-unique only has an effect when -Zmiri-tree-borrows is also used"
);
}
// Tree Borrows implies strict provenance, and is not compatible with native calls.
if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) {
if miri_config.provenance_mode != ProvenanceMode::Strict {

View file

@ -102,8 +102,6 @@ pub struct GlobalStateInner {
tracked_pointer_tags: FxHashSet<BorTag>,
/// Whether to recurse into datatypes when searching for pointers to retag.
retag_fields: RetagFields,
/// Whether `core::ptr::Unique` gets special (`Box`-like) handling.
unique_is_unique: bool,
}
impl VisitProvenance for GlobalStateInner {
@ -164,7 +162,6 @@ impl GlobalStateInner {
borrow_tracker_method: BorrowTrackerMethod,
tracked_pointer_tags: FxHashSet<BorTag>,
retag_fields: RetagFields,
unique_is_unique: bool,
) -> Self {
GlobalStateInner {
borrow_tracker_method,
@ -173,7 +170,6 @@ impl GlobalStateInner {
protected_tags: FxHashMap::default(),
tracked_pointer_tags,
retag_fields,
unique_is_unique,
}
}
@ -239,7 +235,6 @@ impl BorrowTrackerMethod {
self,
config.tracked_pointer_tags.clone(),
config.retag_fields,
config.unique_is_unique,
))
}
}

View file

@ -2,7 +2,6 @@ use rustc_abi::{BackendRepr, Size};
use rustc_middle::mir::{Mutability, RetagKind};
use rustc_middle::ty::layout::HasTypingEnv;
use rustc_middle::ty::{self, Ty};
use rustc_span::def_id::DefId;
use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind};
use crate::concurrency::data_race::NaReadType;
@ -115,9 +114,6 @@ impl<'tcx> Tree {
/// Policy for a new borrow.
#[derive(Debug, Clone, Copy)]
struct NewPermission {
/// Optionally ignore the actual size to do a zero-size reborrow.
/// If this is set then `dereferenceable` is not enforced.
zero_size: bool,
/// Which permission should the pointer start with.
initial_state: Permission,
/// Whether this pointer is part of the arguments of a function call.
@ -157,7 +153,7 @@ impl<'tcx> NewPermission {
};
let protector = is_protected.then_some(ProtectorKind::StrongProtector);
Some(Self { zero_size: false, initial_state, protector, initial_read })
Some(Self { initial_state, protector, initial_read })
}
/// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
@ -167,7 +163,6 @@ impl<'tcx> NewPermission {
ty: Ty<'tcx>,
kind: RetagKind,
cx: &crate::MiriInterpCx<'tcx>,
zero_size: bool,
) -> Option<Self> {
let pointee = ty.builtin_deref(true).unwrap();
pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| {
@ -177,7 +172,6 @@ impl<'tcx> NewPermission {
let protected = kind == RetagKind::FnEntry;
let initial_state = Permission::new_reserved(ty_is_freeze, protected);
Self {
zero_size,
initial_state,
protector: protected.then_some(ProtectorKind::WeakProtector),
initial_read: true,
@ -341,15 +335,12 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Determine the size of the reborrow.
// For most types this is the entire size of the place, however
// - when `extern type` is involved we use the size of the known prefix,
// - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set
// then we override the size to do a zero-length reborrow.
let reborrow_size = match new_perm {
NewPermission { zero_size: false, .. } =>
this.size_and_align_of_mplace(place)?
.map(|(size, _)| size)
.unwrap_or(place.layout.size),
_ => Size::from_bytes(0),
};
// - if the pointer is not reborrowed (raw pointer) then we override the size
// to do a zero-length reborrow.
let reborrow_size = this
.size_and_align_of_mplace(place)?
.map(|(size, _)| size)
.unwrap_or(place.layout.size);
trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
// This new tag is not guaranteed to actually be used.
@ -413,9 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_mut();
let options = this.machine.borrow_tracker.as_mut().unwrap().get_mut();
let retag_fields = options.retag_fields;
let unique_did =
options.unique_is_unique.then(|| this.tcx.lang_items().ptr_unique()).flatten();
let mut visitor = RetagVisitor { ecx: this, kind, retag_fields, unique_did };
let mut visitor = RetagVisitor { ecx: this, kind, retag_fields };
return visitor.visit_value(place);
// The actual visitor.
@ -423,7 +412,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
ecx: &'ecx mut MiriInterpCx<'tcx>,
kind: RetagKind,
retag_fields: RetagFields,
unique_did: Option<DefId>,
}
impl<'ecx, 'tcx> RetagVisitor<'ecx, 'tcx> {
#[inline(always)] // yes this helps in our benchmarks
@ -454,12 +442,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
// Only boxes for the global allocator get any special treatment.
if box_ty.is_box_global(*self.ecx.tcx) {
let new_perm = NewPermission::from_unique_ty(
place.layout.ty,
self.kind,
self.ecx,
/* zero_size */ false,
);
let new_perm =
NewPermission::from_unique_ty(place.layout.ty, self.kind, self.ecx);
self.retag_ptr_inplace(place, new_perm)?;
}
interp_ok(())
@ -493,16 +477,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// even if field retagging is not enabled. *shrug*)
self.walk_value(place)?;
}
ty::Adt(adt, _) if self.unique_did == Some(adt.did()) => {
let place = inner_ptr_of_unique(self.ecx, place)?;
let new_perm = NewPermission::from_unique_ty(
place.layout.ty,
self.kind,
self.ecx,
/* zero_size */ true,
);
self.retag_ptr_inplace(&place, new_perm)?;
}
_ => {
// Not a reference/pointer/box. Only recurse if configured appropriately.
let recurse = match self.retag_fields {
@ -541,7 +515,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Retag it. With protection! That is the entire point.
let new_perm = NewPermission {
initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true),
zero_size: false,
protector: Some(ProtectorKind::StrongProtector),
initial_read: true,
};
@ -603,27 +576,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
tree_borrows.give_pointer_debug_name(tag, nth_parent, name)
}
}
/// Takes a place for a `Unique` and turns it into a place with the inner raw pointer.
/// I.e. input is what you get from the visitor upon encountering an `adt` that is `Unique`,
/// and output can be used by `retag_ptr_inplace`.
fn inner_ptr_of_unique<'tcx>(
ecx: &MiriInterpCx<'tcx>,
place: &PlaceTy<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx>> {
// Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in
// `rustc_const_eval`, just with one fewer layer.
// Here we have a `Unique(NonNull(*mut), PhantomData)`
assert_eq!(place.layout.fields.count(), 2, "Unique must have exactly 2 fields");
let (nonnull, phantom) = (ecx.project_field(place, 0)?, ecx.project_field(place, 1)?);
assert!(
phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
"2nd field of `Unique` should be `PhantomData` but is `{:?}`",
phantom.layout.ty,
);
// Now down to `NonNull(*mut)`
assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field");
let ptr = ecx.project_field(&nonnull, 0)?;
// Finally a plain `*mut`
interp_ok(ptr)
}

View file

@ -101,10 +101,6 @@ pub struct MiriConfig {
pub validation: ValidationMode,
/// Determines if Stacked Borrows or Tree Borrows is enabled.
pub borrow_tracker: Option<BorrowTrackerMethod>,
/// Whether `core::ptr::Unique` receives special treatment.
/// If `true` then `Unique` is reborrowed with its own new tag and permission,
/// otherwise `Unique` is just another raw pointer.
pub unique_is_unique: bool,
/// Controls alignment checking.
pub check_alignment: AlignmentCheck,
/// Action for an op requiring communication with the host.
@ -177,7 +173,6 @@ impl Default for MiriConfig {
env: vec![],
validation: ValidationMode::Shallow,
borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows),
unique_is_unique: false,
check_alignment: AlignmentCheck::Int,
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
ignore_leaks: false,

View file

@ -1,15 +0,0 @@
error: Undefined Behavior: entering unreachable code
--> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
|
LL | std::hint::unreachable_unchecked();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `main` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -1,58 +0,0 @@
//@revisions: default uniq
//@compile-flags: -Zmiri-tree-borrows
//@[uniq]compile-flags: -Zmiri-unique-is-unique
//! This is NOT intended behavior.
//! We should eventually find a solution so that the version with `Unique` passes too,
//! otherwise `Unique` is more strict than `&mut`!
#![feature(ptr_internals)]
use core::ptr::{Unique, addr_of_mut};
fn main() {
let mut data = 0u8;
let raw = addr_of_mut!(data);
unsafe {
raw_children_of_refmut_can_alias(&mut *raw);
raw_children_of_unique_can_alias(Unique::new_unchecked(raw));
// Ultimately the intended behavior is that both above tests would
// succeed.
std::hint::unreachable_unchecked();
//~[default]^ ERROR: entering unreachable code
}
}
unsafe fn raw_children_of_refmut_can_alias(x: &mut u8) {
let child1 = addr_of_mut!(*x);
let child2 = addr_of_mut!(*x);
// We create two raw aliases of `x`: they have the exact same
// tag and can be used interchangeably.
child1.write(1);
child2.write(2);
child1.write(1);
child2.write(2);
}
unsafe fn raw_children_of_unique_can_alias(x: Unique<u8>) {
let child1 = x.as_ptr();
let child2 = x.as_ptr();
// Under `-Zmiri-unique-is-unique`, `Unique` accidentally offers more guarantees
// than `&mut`. Not because it responds differently to accesses but because
// there is no easy way to obtain a copy with the same tag.
//
// The closest (non-hack) attempt is two calls to `as_ptr`.
// - Without `-Zmiri-unique-is-unique`, independent `as_ptr` calls return pointers
// with the same tag that can thus be used interchangeably.
// - With the current implementation of `-Zmiri-unique-is-unique`, they return cousin
// tags with permissions that do not tolerate aliasing.
// Eventually we should make such aliasing allowed in some situations
// (e.g. when there is no protector), which will probably involve
// introducing a new kind of permission.
child1.write(1);
child2.write(2);
//~[uniq]^ ERROR: /write access through .* is forbidden/
child1.write(1);
child2.write(2);
}

View file

@ -1,31 +0,0 @@
error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
--> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
|
LL | child2.write(2);
| ^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
help: the accessed tag <TAG> was created here, in the initial state Reserved
--> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
|
LL | let child2 = x.as_ptr();
| ^^^^^^^^^^
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1]
--> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
|
LL | child1.write(1);
| ^^^^^^^^^^^^^^^
= help: this transition corresponds to a loss of read and write permissions
= note: BACKTRACE (of the first span):
= note: inside `raw_children_of_unique_can_alias` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC
note: inside `main`
--> tests/fail/tree_borrows/children-can-alias.rs:LL:CC
|
LL | raw_children_of_unique_can_alias(Unique::new_unchecked(raw));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -1,27 +0,0 @@
//@revisions: default uniq
//@compile-flags: -Zmiri-tree-borrows
//@[uniq]compile-flags: -Zmiri-unique-is-unique
// A pattern that detects if `Unique` is treated as exclusive or not:
// activate the pointer behind a `Unique` then do a read that is parent
// iff `Unique` was specially reborrowed.
#![feature(ptr_internals)]
use core::ptr::Unique;
fn main() {
let mut data = 0u8;
let refmut = &mut data;
let rawptr = refmut as *mut u8;
unsafe {
let uniq = Unique::new_unchecked(rawptr);
*uniq.as_ptr() = 1; // activation
let _maybe_parent = *rawptr; // maybe becomes Frozen
*uniq.as_ptr() = 2;
//~[uniq]^ ERROR: /write access through .* is forbidden/
let _definitely_parent = data; // definitely Frozen by now
*uniq.as_ptr() = 3;
//~[default]^ ERROR: /write access through .* is forbidden/
}
}

View file

@ -1,38 +0,0 @@
error: Undefined Behavior: write access through <TAG> at ALLOC[0x0] is forbidden
--> tests/fail/tree_borrows/unique.rs:LL:CC
|
LL | *uniq.as_ptr() = 2;
| ^^^^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
= help: the conflicting tag <TAG> has state Frozen which forbids this child write access
help: the accessed tag <TAG> was created here
--> tests/fail/tree_borrows/unique.rs:LL:CC
|
LL | *uniq.as_ptr() = 2;
| ^^^^^^^^^^^^^
help: the conflicting tag <TAG> was created here, in the initial state Reserved
--> tests/fail/tree_borrows/unique.rs:LL:CC
|
LL | let uniq = Unique::new_unchecked(rawptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
--> tests/fail/tree_borrows/unique.rs:LL:CC
|
LL | *uniq.as_ptr() = 1; // activation
| ^^^^^^^^^^^^^^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
help: the conflicting tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
--> tests/fail/tree_borrows/unique.rs:LL:CC
|
LL | let _maybe_parent = *rawptr; // maybe becomes Frozen
| ^^^^^^^
= help: this transition corresponds to a loss of write permissions
= note: BACKTRACE (of the first span):
= note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error

View file

@ -1,6 +1,4 @@
//@revisions: default uniq
//@compile-flags: -Zmiri-tree-borrows
//@[uniq]compile-flags: -Zmiri-unique-is-unique
#![allow(dangerous_implicit_autorefs)]
use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
use std::mem::{self, MaybeUninit};

View file

@ -1,6 +1,4 @@
//@revisions: default uniq
//@compile-flags: -Zmiri-tree-borrows
//@[uniq]compile-flags: -Zmiri-unique-is-unique
#![feature(allocator_api)]
use std::{mem, ptr};

View file

@ -1,21 +0,0 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Res | └─┬──<TAG=base>
| Res | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └────<TAG=raw, uniq, uniq>
──────────────────────────────────────────────────

View file

@ -1,67 +0,0 @@
//@revisions: default uniq
// We disable the GC for this test because it would change what is printed.
//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
//@[uniq]compile-flags: -Zmiri-unique-is-unique
#![feature(ptr_internals)]
#[path = "../../utils/mod.rs"]
#[macro_use]
mod utils;
use core::ptr::Unique;
// Check general handling of Unique
fn main() {
unsafe {
let base = &mut 5u8;
let alloc_id = alloc_id!(base);
name!(base);
let raw = &mut *base as *mut u8;
name!(raw);
// We create a `Unique` and expect it to have a fresh tag
// and uninitialized permissions.
let uniq = Unique::new_unchecked(raw);
// With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by
// `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual
// `base` pointer we care about we have to walk up the tree a bit.
//
// We care about naming this specific parent tag because it is the one
// that stays `Active` during the entire execution, unlike the leaves
// that will be invalidated the next time `as_ptr` is called.
//
// (We name it twice so that we have an indicator in the output of
// whether we got the distance correct:
// If the output shows
//
// |- <XYZ: uniq>
// '- <XYZ: uniq>
//
// then `nth_parent` is not big enough.
// The correct value for `nth_parent` should be the minimum
// integer for which the output shows
//
// '- <XYZ: uniq, uniq>
// )
//
// Ultimately we want pointers obtained through independent
// calls of `as_ptr` to be able to alias, which will probably involve
// a new permission that allows aliasing when there is no protector.
let nth_parent = if cfg!(uniq) { 2 } else { 0 };
name!(uniq.as_ptr()=>nth_parent, "uniq");
name!(uniq.as_ptr()=>nth_parent, "uniq");
print_state!(alloc_id);
// We can activate the Unique and use it mutably.
*uniq.as_ptr() = 42;
print_state!(alloc_id);
// Write through the raw parent disables the Unique
*raw = 42;
print_state!(alloc_id);
}
}

View file

@ -1,24 +0,0 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Res | └─┬──<TAG=base>
| Res | └─┬──<TAG=raw>
|-----| └────<TAG=uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └─┬──<TAG=raw>
| Act | └────<TAG=uniq, uniq>
──────────────────────────────────────────────────
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 1
| Act | └─┬──<TAG=root of the allocation>
| Act | └─┬──<TAG=base>
| Act | └─┬──<TAG=raw>
| Dis | └────<TAG=uniq, uniq>
──────────────────────────────────────────────────

View file

@ -1,69 +0,0 @@
//@revisions: default uniq
// We disable the GC for this test because it would change what is printed.
//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0
//@[uniq]compile-flags: -Zmiri-unique-is-unique
#![feature(vec_into_raw_parts)]
#[path = "../../utils/mod.rs"]
#[macro_use]
mod utils;
// Check general handling of `Unique`:
// there is no *explicit* `Unique` being used here, but there is one
// hidden a few layers inside `Vec` that should be reflected in the tree structure.
fn main() {
unsafe {
let base = vec![0u8, 1];
let alloc_id = alloc_id!(base.as_ptr());
// With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by
// `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual
// `base` pointer we care about we have to walk up the tree a bit.
//
// We care about naming this specific parent tag because it is the one
// that stays `Active` during the entire execution, unlike the leaves
// that will be invalidated the next time `as_ptr` is called.
//
// (We name it twice so that we have an indicator in the output of
// whether we got the distance correct:
// If the output shows
//
// ├─ <TAG=base.as_ptr()>
// └─ <TAG=base.as_ptr()>
//
// then `nth_parent` is not big enough.
// The correct value for `nth_parent` should be the minimum
// integer for which the output shows
//
// └─ <TAG=base.as_ptr(), base.as_ptr(), ...>
// )
//
// Ultimately we want pointers obtained through independent
// calls of `as_ptr` to be able to alias, which will probably involve
// a new permission that allows aliasing when there is no protector.
let nth_parent = if cfg!(uniq) { 9 } else { 0 };
name!(base.as_ptr()=>nth_parent);
name!(base.as_ptr()=>nth_parent);
// Destruct the `Vec`
let (ptr, len, cap) = base.into_raw_parts();
// Expect this to be again the same pointer as the one obtained from `as_ptr`.
// Under `-Zmiri-unique-is-unique`, this will be a strict child.
name!(ptr, "raw_parts.0");
// This is where the presence of `Unique` has implications,
// because there will be a reborrow here iff the exclusivity of `Unique`
// is enforced.
let reconstructed = Vec::from_raw_parts(ptr, len, cap);
// The `as_ptr` here (twice for the same reason as above) return either
// the same pointer once more (default) or a strict child (uniq).
name!(reconstructed.as_ptr()=>nth_parent);
name!(reconstructed.as_ptr()=>nth_parent);
print_state!(alloc_id, false);
}
}

View file

@ -1,8 +0,0 @@
──────────────────────────────────────────────────
Warning: this tree is indicative only. Some tags may have been hidden.
0.. 2
| Act | └─┬──<TAG=root of the allocation>
|-----| └─┬──<TAG=base.as_ptr(), base.as_ptr()>
|-----| └─┬──<TAG=raw_parts.0>
|-----| └────<TAG=reconstructed.as_ptr(), reconstructed.as_ptr()>
──────────────────────────────────────────────────

View file

@ -1,7 +1,6 @@
//@revisions: stack tree tree_uniq
//@revisions: stack tree
//@compile-flags: -Zmiri-strict-provenance
//@[tree]compile-flags: -Zmiri-tree-borrows
//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique
#![feature(iter_advance_by, iter_next_chunk)]
// Gather all references from a mutable iterator and make sure Miri notices if

View file

@ -1,8 +1,6 @@
//@revisions: stack tree tree_uniq
//@revisions: stack tree
//@compile-flags: -Zmiri-strict-provenance
//@[tree]compile-flags: -Zmiri-tree-borrows
//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique
use std::collections::VecDeque;
fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {