diff options
| author | bors <bors@rust-lang.org> | 2025-09-23 21:37:04 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-09-23 21:37:04 +0000 |
| commit | ae12bc21d8ec76bbb753d4da168e9b08e1b09ebf (patch) | |
| tree | b0d73554bf14e164cebceb6c47ffdd33335afe69 /src/tools/miri/tests | |
| parent | 975e6c8fec280816d24fbde6b8dfe19620f2efe6 (diff) | |
| parent | 85be36c1d38028b7be1d63f895f269c61d8953d4 (diff) | |
Auto merge of #146931 - RalfJung:miri, r=RalfJung
miri subtree update Subtree update of `miri` to https://github.com/rust-lang/miri/commit/f6466ce655ff6b203de81ba6f4cbfe8d8dd6756f. Created using https://github.com/rust-lang/josh-sync. r? `@ghost`
Diffstat (limited to 'src/tools/miri/tests')
26 files changed, 214 insertions, 298 deletions
diff --git a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr index 449a29088a0..dc8b4f6665a 100644 --- a/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr +++ b/src/tools/miri/tests/fail/async-shared-mutable.tree.stderr @@ -16,7 +16,7 @@ LL | | Poll::<()>::Pending LL | | }) LL | | .await | |______________^ -help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [OFFSET] +help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [OFFSET] --> tests/fail/async-shared-mutable.rs:LL:CC | LL | *x = 1; diff --git a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr index 3c8ec7f7d3e..6a1f7761a41 100644 --- a/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/box_noalias_violation.tree.stderr @@ -7,7 +7,7 @@ LL | *y = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | unsafe fn test(mut x: Box<i32>, y: *const i32) -> i32 { | ^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/both_borrows/box_noalias_violation.rs:LL:CC | LL | *x = 5; diff --git a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr index 6780e52c3ba..1547a6ca73a 100644 --- a/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/illegal_write6.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { *y = 2 }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/both_borrows/illegal_write6.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/both_borrows/illegal_write6.rs:LL:CC | LL | *a = 1; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr index 2266a9c39f9..2d9ce2aa1fb 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias.tree.stderr @@ -7,7 +7,7 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | y.0 = 0; | ^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC | LL | y.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr index b7f514de0af..42e391b5daf 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_locals_alias_ret.tree.stderr @@ -7,7 +7,7 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this reborrow (acting as a foreign read access) would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC @@ -19,7 +19,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | x | ^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC | LL | x diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr index 1995528e9f9..74706d6b9f6 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_mutate.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(S(0)) }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | unsafe { ptr.write(S(0)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC | LL | unsafe { ptr.write(S(0)) }; diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr index e506a61c6bb..c8c0e5c37ef 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | x.0 = 0; | ^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | x.0 = 0; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr index b1aa2ba2886..b43e19c3905 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.read() }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign read access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | unsafe { ptr.read() }; | ^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr index 0cf449ea3ec..deefb24b785 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC | LL | unsafe { ptr.write(0) }; diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr index a006c6feae4..76ccf39744d 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_write_tail_call.tree.stderr @@ -7,7 +7,7 @@ LL | unsafe { ptr.write(0) }; = 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: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) - = help: this foreign write access would cause the protected tag <TAG> (currently Active) to become Disabled + = help: this foreign write access would cause the protected tag <TAG> (currently Unique) to become Disabled = help: protected tags must never be Disabled help: the accessed tag <TAG> was created here --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC @@ -24,7 +24,7 @@ help: the protected tag <TAG> was created here, in the initial state Reserved | LL | unsafe { ptr.write(0) }; | ^^^^^^^^^^^^^^^^^^^^^^^ -help: the protected tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC | LL | unsafe { ptr.write(0) }; diff --git a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr index 9e955a6d5b1..aff482abfa0 100644 --- a/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/alternate-read-write.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved | LL | let y = unsafe { &mut *(x as *mut u8) }; | ^^^^^^^^^^^^^^^^^^^^ -help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1] +help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x1] --> tests/fail/tree_borrows/alternate-read-write.rs:LL:CC | LL | *y += 1; // Success diff --git a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr index 7886029dccf..bfd6854514e 100644 --- a/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/fnentry_invalidation.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved | LL | let z = &mut x as *mut i32; | ^^^^^^ -help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/tree_borrows/fnentry_invalidation.rs:LL:CC | LL | *z = 1; diff --git a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr index 2edbbd80569..7a713abcbc4 100644 --- a/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/parent_read_freezes_raw_mut.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved | LL | let mref = &mut root; | ^^^^^^^^^ -help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1] +help: the accessed tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x1] --> tests/fail/tree_borrows/parent_read_freezes_raw_mut.rs:LL:CC | LL | *ptr = 0; // Write diff --git a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr index c00c67173b7..9a70d248aa0 100644 --- a/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/pass_invalid_mut.stderr @@ -18,7 +18,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x4] +help: the conflicting tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4] --> tests/fail/tree_borrows/pass_invalid_mut.rs:LL:CC | LL | *xref = 18; // activate xref diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 024a14600b1..3e5d83911ee 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -60,8 +60,7 @@ fn main() { fn inner(x: &mut u8, b: IdxBarrier) { *x = 42; // activate immediately synchronized!(b, "[lazy] retag y (&mut, protect, IM)"); - // A spurious write should be valid here because `x` is - // `Active` and protected. + // A spurious write should be valid here because `x` is `Unique` and protected. if cfg!(with) { synchronized!(b, "spurious write x (executed)"); *x = 64; diff --git a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr index ba8ab472872..4b6308847bb 100644 --- a/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/return_invalid_mut.stderr @@ -18,7 +18,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ -help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x4..0x8] +help: the conflicting tag <TAG> later transitioned to Unique due to a child write access at offsets [0x4..0x8] --> tests/fail/tree_borrows/return_invalid_mut.rs:LL:CC | LL | *ret = *ret; // activate diff --git a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs index 6514334b09d..94a3bb80544 100644 --- a/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs +++ b/src/tools/miri/tests/fail/tree_borrows/subtree_traversal_skipping_diagnostics.rs @@ -5,7 +5,7 @@ // When this method is called, the tree will be a single line and look like this, // with other_ptr being the root at the top -// other_ptr = root : Active +// other_ptr = root : Unique // intermediary : Frozen // an intermediary node // m : Reserved fn write_to_mut(m: &mut u8, other_ptr: *const u8) { diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr deleted file mode 100644 index c7d72f70f40..00000000000 --- a/src/tools/miri/tests/fail/tree_borrows/unique.default.stderr +++ /dev/null @@ -1,32 +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() = 3; - | ^^^^^^^^^^^^^^^^^^ 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 Frozen which forbids this child write access -help: the accessed tag <TAG> was created here, in the initial state Reserved - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | let refmut = &mut data; - | ^^^^^^^^^ -help: the accessed 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 accessed 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 _definitely_parent = data; // definitely Frozen by now - | ^^^^ - = 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 - diff --git a/src/tools/miri/tests/pass/0weak_memory/weak.rs b/src/tools/miri/tests/pass/0weak_memory/weak.rs index c752fc114ba..611733d0dac 100644 --- a/src/tools/miri/tests/pass/0weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/0weak_memory/weak.rs @@ -13,6 +13,10 @@ use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicUsize, fence}; use std::thread::spawn; +#[path = "../../utils/mod.rs"] +mod utils; +use utils::check_all_outcomes; + #[allow(dead_code)] #[derive(Copy, Clone)] struct EvilSend<T>(pub T); @@ -33,35 +37,6 @@ fn spin_until(loc: &AtomicUsize, val: usize) -> usize { val } -/// Check that the function produces the intended set of outcomes. -#[track_caller] -fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>( - expected: impl IntoIterator<Item = T>, - generate: impl Fn() -> T, -) { - use std::collections::HashSet; - - let expected: HashSet<T> = HashSet::from_iter(expected); - let mut seen = HashSet::new(); - // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 16; - for i in 0..tries { - let val = generate(); - assert!(expected.contains(&val), "got an unexpected value: {val:?}"); - seen.insert(val); - if i > tries / 2 && expected.len() == seen.len() { - // We saw everything and we did quite a few tries, let's avoid wasting time. - return; - } - } - // Let's see if we saw them all. - for val in expected { - if !seen.contains(&val) { - panic!("did not get value that should be possible: {val:?}"); - } - } -} - fn relaxed() { check_all_outcomes([0, 1, 2], || { let x = static_atomic(0); diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 3a764329f9b..67a14c2b389 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -8,12 +8,16 @@ #![allow(internal_features)] #![allow(unnecessary_transmutes)] +#[path = "../utils/mod.rs"] +mod utils; use std::any::type_name; use std::cmp::min; use std::fmt::{Debug, Display, LowerHex}; use std::hint::black_box; use std::{f32, f64}; +use utils::check_nondet; + /// Compare the two floats, allowing for $ulp many ULPs of error. /// /// ULP means "Units in the Last Place" or "Units of Least Precision". @@ -1429,29 +1433,14 @@ fn test_fmuladd() { /// `min` and `max` on equal arguments are non-deterministic. fn test_min_max_nondet() { - /// Ensure that if we call the closure often enough, we see both `true` and `false.` - #[track_caller] - fn ensure_both(f: impl Fn() -> bool) { - let rounds = 32; - let first = f(); - for _ in 1..rounds { - if f() != first { - // We saw two different values! - return; - } - } - // We saw the same thing N times. - panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); - } - - ensure_both(|| f16::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f16::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f32::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f32::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f64::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f64::max(0.0, -0.0).is_sign_positive()); - ensure_both(|| f128::min(0.0, -0.0).is_sign_positive()); - ensure_both(|| f128::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f16::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f16::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f32::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f64::max(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::min(0.0, -0.0).is_sign_positive()); + check_nondet(|| f128::max(0.0, -0.0).is_sign_positive()); } fn test_non_determinism() { @@ -1461,35 +1450,20 @@ fn test_non_determinism() { }; use std::{f32, f64}; - /// Ensure that the operation is non-deterministic - #[track_caller] - fn ensure_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) { - let rounds = 16; - let first = f(); - for _ in 1..rounds { - if f() != first { - // We saw two different values! - return; - } - } - // We saw the same thing N times. - panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); - } - macro_rules! test_operations_f { ($a:expr, $b:expr) => { - ensure_nondet(|| fadd_algebraic($a, $b)); - ensure_nondet(|| fsub_algebraic($a, $b)); - ensure_nondet(|| fmul_algebraic($a, $b)); - ensure_nondet(|| fdiv_algebraic($a, $b)); - ensure_nondet(|| frem_algebraic($a, $b)); + check_nondet(|| fadd_algebraic($a, $b)); + check_nondet(|| fsub_algebraic($a, $b)); + check_nondet(|| fmul_algebraic($a, $b)); + check_nondet(|| fdiv_algebraic($a, $b)); + check_nondet(|| frem_algebraic($a, $b)); unsafe { - ensure_nondet(|| fadd_fast($a, $b)); - ensure_nondet(|| fsub_fast($a, $b)); - ensure_nondet(|| fmul_fast($a, $b)); - ensure_nondet(|| fdiv_fast($a, $b)); - ensure_nondet(|| frem_fast($a, $b)); + check_nondet(|| fadd_fast($a, $b)); + check_nondet(|| fsub_fast($a, $b)); + check_nondet(|| fmul_fast($a, $b)); + check_nondet(|| fdiv_fast($a, $b)); + check_nondet(|| frem_fast($a, $b)); } }; } @@ -1499,70 +1473,70 @@ fn test_non_determinism() { } pub fn test_operations_f32(a: f32, b: f32) { test_operations_f!(a, b); - ensure_nondet(|| a.powf(b)); - ensure_nondet(|| a.powi(2)); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 10f32.exp2()); - ensure_nondet(|| f32::consts::E.ln()); - ensure_nondet(|| 10f32.log10()); - ensure_nondet(|| 8f32.log2()); - ensure_nondet(|| 1f32.ln_1p()); - ensure_nondet(|| 27.0f32.cbrt()); - ensure_nondet(|| 3.0f32.hypot(4.0f32)); - ensure_nondet(|| 1f32.sin()); - ensure_nondet(|| 1f32.cos()); + check_nondet(|| a.powf(b)); + check_nondet(|| a.powi(2)); + check_nondet(|| a.log(b)); + check_nondet(|| a.exp()); + check_nondet(|| 10f32.exp2()); + check_nondet(|| f32::consts::E.ln()); + check_nondet(|| 10f32.log10()); + check_nondet(|| 8f32.log2()); + check_nondet(|| 1f32.ln_1p()); + check_nondet(|| 27.0f32.cbrt()); + check_nondet(|| 3.0f32.hypot(4.0f32)); + check_nondet(|| 1f32.sin()); + check_nondet(|| 1f32.cos()); // On i686-pc-windows-msvc , these functions are implemented by calling the `f64` version, // which means the little rounding errors Miri introduces are discarded by the cast down to // `f32`. Just skip the test for them. if !cfg!(all(target_os = "windows", target_env = "msvc", target_arch = "x86")) { - ensure_nondet(|| 1.0f32.tan()); - ensure_nondet(|| 1.0f32.asin()); - ensure_nondet(|| 5.0f32.acos()); - ensure_nondet(|| 1.0f32.atan()); - ensure_nondet(|| 1.0f32.atan2(2.0f32)); - ensure_nondet(|| 1.0f32.sinh()); - ensure_nondet(|| 1.0f32.cosh()); - ensure_nondet(|| 1.0f32.tanh()); + check_nondet(|| 1.0f32.tan()); + check_nondet(|| 1.0f32.asin()); + check_nondet(|| 5.0f32.acos()); + check_nondet(|| 1.0f32.atan()); + check_nondet(|| 1.0f32.atan2(2.0f32)); + check_nondet(|| 1.0f32.sinh()); + check_nondet(|| 1.0f32.cosh()); + check_nondet(|| 1.0f32.tanh()); } - ensure_nondet(|| 1.0f32.asinh()); - ensure_nondet(|| 2.0f32.acosh()); - ensure_nondet(|| 0.5f32.atanh()); - ensure_nondet(|| 5.0f32.gamma()); - ensure_nondet(|| 5.0f32.ln_gamma()); - ensure_nondet(|| 5.0f32.erf()); - ensure_nondet(|| 5.0f32.erfc()); + check_nondet(|| 1.0f32.asinh()); + check_nondet(|| 2.0f32.acosh()); + check_nondet(|| 0.5f32.atanh()); + check_nondet(|| 5.0f32.gamma()); + check_nondet(|| 5.0f32.ln_gamma()); + check_nondet(|| 5.0f32.erf()); + check_nondet(|| 5.0f32.erfc()); } pub fn test_operations_f64(a: f64, b: f64) { test_operations_f!(a, b); - ensure_nondet(|| a.powf(b)); - ensure_nondet(|| a.powi(2)); - ensure_nondet(|| a.log(b)); - ensure_nondet(|| a.exp()); - ensure_nondet(|| 50f64.exp2()); - ensure_nondet(|| 3f64.ln()); - ensure_nondet(|| f64::consts::E.log10()); - ensure_nondet(|| f64::consts::E.log2()); - ensure_nondet(|| 1f64.ln_1p()); - ensure_nondet(|| 27.0f64.cbrt()); - ensure_nondet(|| 3.0f64.hypot(4.0f64)); - ensure_nondet(|| 1f64.sin()); - ensure_nondet(|| 1f64.cos()); - ensure_nondet(|| 1.0f64.tan()); - ensure_nondet(|| 1.0f64.asin()); - ensure_nondet(|| 5.0f64.acos()); - ensure_nondet(|| 1.0f64.atan()); - ensure_nondet(|| 1.0f64.atan2(2.0f64)); - ensure_nondet(|| 1.0f64.sinh()); - ensure_nondet(|| 1.0f64.cosh()); - ensure_nondet(|| 1.0f64.tanh()); - ensure_nondet(|| 1.0f64.asinh()); - ensure_nondet(|| 3.0f64.acosh()); - ensure_nondet(|| 0.5f64.atanh()); - ensure_nondet(|| 5.0f64.gamma()); - ensure_nondet(|| 5.0f64.ln_gamma()); - ensure_nondet(|| 5.0f64.erf()); - ensure_nondet(|| 5.0f64.erfc()); + check_nondet(|| a.powf(b)); + check_nondet(|| a.powi(2)); + check_nondet(|| a.log(b)); + check_nondet(|| a.exp()); + check_nondet(|| 50f64.exp2()); + check_nondet(|| 3f64.ln()); + check_nondet(|| f64::consts::E.log10()); + check_nondet(|| f64::consts::E.log2()); + check_nondet(|| 1f64.ln_1p()); + check_nondet(|| 27.0f64.cbrt()); + check_nondet(|| 3.0f64.hypot(4.0f64)); + check_nondet(|| 1f64.sin()); + check_nondet(|| 1f64.cos()); + check_nondet(|| 1.0f64.tan()); + check_nondet(|| 1.0f64.asin()); + check_nondet(|| 5.0f64.acos()); + check_nondet(|| 1.0f64.atan()); + check_nondet(|| 1.0f64.atan2(2.0f64)); + check_nondet(|| 1.0f64.sinh()); + check_nondet(|| 1.0f64.cosh()); + check_nondet(|| 1.0f64.tanh()); + check_nondet(|| 1.0f64.asinh()); + check_nondet(|| 3.0f64.acosh()); + check_nondet(|| 0.5f64.atanh()); + check_nondet(|| 5.0f64.gamma()); + check_nondet(|| 5.0f64.ln_gamma()); + check_nondet(|| 5.0f64.erf()); + check_nondet(|| 5.0f64.erfc()); } pub fn test_operations_f128(a: f128, b: f128) { test_operations_f!(a, b); @@ -1574,15 +1548,15 @@ fn test_non_determinism() { test_operations_f128(25., 18.); // SNaN^0 = (1 | NaN) - ensure_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); - ensure_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); + check_nondet(|| f32::powf(SNAN_F32, 0.0).is_nan()); + check_nondet(|| f64::powf(SNAN_F64, 0.0).is_nan()); // 1^SNaN = (1 | NaN) - ensure_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); - ensure_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); + check_nondet(|| f32::powf(1.0, SNAN_F32).is_nan()); + check_nondet(|| f64::powf(1.0, SNAN_F64).is_nan()); // same as powf (keep it consistent): // x^SNaN = (1 | NaN) - ensure_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); - ensure_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); + check_nondet(|| f32::powi(SNAN_F32, 0).is_nan()); + check_nondet(|| f64::powi(SNAN_F64, 0).is_nan()); } diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 90281630740..c07ffdf9740 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -5,6 +5,10 @@ use std::fmt; use std::hint::black_box; +#[path = "../utils/mod.rs"] +mod utils; +use utils::check_all_outcomes; + fn ldexp(a: f64, b: i32) -> f64 { extern "C" { fn ldexp(x: f64, n: i32) -> f64; @@ -26,35 +30,6 @@ enum NaNKind { } use NaNKind::*; -/// Check that the function produces the intended set of outcomes. -#[track_caller] -fn check_all_outcomes<T: Eq + std::hash::Hash + fmt::Display>( - expected: impl IntoIterator<Item = T>, - generate: impl Fn() -> T, -) { - use std::collections::HashSet; - - let expected: HashSet<T> = HashSet::from_iter(expected); - let mut seen = HashSet::new(); - // Let's give it N times as many tries as we are expecting values. - let tries = expected.len() * 12; - for i in 0..tries { - let val = generate(); - assert!(expected.contains(&val), "got an unexpected value: {val}"); - seen.insert(val); - if i > tries / 2 && expected.len() == seen.len() { - // We saw everything and we did quite a few tries, let's avoid wasting time. - return; - } - } - // Let's see if we saw them all. - for val in expected { - if !seen.contains(&val) { - panic!("did not get value that should be possible: {val}"); - } - } -} - // -- f32 support #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq, Hash)] @@ -81,7 +56,7 @@ const F32_EXP: u32 = 8; // 8 bits of exponent const F32_MANTISSA: u32 = F32_SIGN_BIT - F32_EXP; const F32_NAN_PAYLOAD: u32 = F32_MANTISSA - 1; -impl fmt::Display for F32 { +impl fmt::Debug for F32 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Alaways show raw bits. write!(f, "0x{:08x} ", self.0)?; @@ -154,7 +129,7 @@ const F64_EXP: u32 = 11; // 11 bits of exponent const F64_MANTISSA: u32 = F64_SIGN_BIT - F64_EXP; const F64_NAN_PAYLOAD: u32 = F64_MANTISSA - 1; -impl fmt::Display for F64 { +impl fmt::Debug for F64 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Alaways show raw bits. write!(f, "0x{:08x} ", self.0)?; diff --git a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs index 4d3e91c4cba..abc156d49cb 100644 --- a/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs +++ b/src/tools/miri/tests/pass/intrinsics/fmuladd_nondeterministic.rs @@ -3,73 +3,48 @@ use std::intrinsics::simd::simd_relaxed_fma; use std::intrinsics::{fmuladdf32, fmuladdf64}; use std::simd::prelude::*; -fn ensure_both_happen(f: impl Fn() -> bool) -> bool { - let mut saw_true = false; - let mut saw_false = false; - for _ in 0..50 { - let b = f(); - if b { - saw_true = true; - } else { - saw_false = true; - } - if saw_true && saw_false { - return true; - } - } - false -} +#[path = "../../utils/mod.rs"] +mod utils; +use utils::check_nondet; fn main() { - assert!( - ensure_both_happen(|| { - let a = std::hint::black_box(0.1_f64); - let b = std::hint::black_box(0.2); - let c = std::hint::black_box(-a * b); - // It is unspecified whether the following operation is fused or not. The - // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. - let x = fmuladdf64(a, b, c); - x == 0.0 - }), - "`fmuladdf64` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = std::hint::black_box(0.1_f64); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused. + let x = fmuladdf64(a, b, c); + x == 0.0 + }); - assert!( - ensure_both_happen(|| { - let a = std::hint::black_box(0.1_f32); - let b = std::hint::black_box(0.2); - let c = std::hint::black_box(-a * b); - // It is unspecified whether the following operation is fused or not. The - // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. - let x = fmuladdf32(a, b, c); - x == 0.0 - }), - "`fmuladdf32` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = std::hint::black_box(0.1_f32); + let b = std::hint::black_box(0.2); + let c = std::hint::black_box(-a * b); + // It is unspecified whether the following operation is fused or not. The + // following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused. + let x = fmuladdf32(a, b, c); + x == 0.0 + }); - assert!( - ensure_both_happen(|| { - let a = f32x4::splat(std::hint::black_box(0.1)); - let b = f32x4::splat(std::hint::black_box(0.2)); - let c = std::hint::black_box(-a * b); - let x = unsafe { simd_relaxed_fma(a, b, c) }; - // Whether we fuse or not is a per-element decision, so sometimes these should be - // the same and sometimes not. - x[0] == x[1] - }), - "`simd_relaxed_fma` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = f32x4::splat(std::hint::black_box(0.1)); + let b = f32x4::splat(std::hint::black_box(0.2)); + let c = std::hint::black_box(-a * b); + let x = unsafe { simd_relaxed_fma(a, b, c) }; + // Whether we fuse or not is a per-element decision, so sometimes these should be + // the same and sometimes not. + x[0] == x[1] + }); - assert!( - ensure_both_happen(|| { - let a = f64x4::splat(std::hint::black_box(0.1)); - let b = f64x4::splat(std::hint::black_box(0.2)); - let c = std::hint::black_box(-a * b); - let x = unsafe { simd_relaxed_fma(a, b, c) }; - // Whether we fuse or not is a per-element decision, so sometimes these should be - // the same and sometimes not. - x[0] == x[1] - }), - "`simd_relaxed_fma` failed to be evaluated as both fused and unfused" - ); + check_nondet(|| { + let a = f64x4::splat(std::hint::black_box(0.1)); + let b = f64x4::splat(std::hint::black_box(0.2)); + let c = std::hint::black_box(-a * b); + let x = unsafe { simd_relaxed_fma(a, b, c) }; + // Whether we fuse or not is a per-element decision, so sometimes these should be + // the same and sometimes not. + x[0] == x[1] + }); } diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs index adf2f4e845b..4a868455c84 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs @@ -20,7 +20,7 @@ pub fn main() { name!(ptr2); // We perform a write through `x`. - // Because `ptr1` is ReservedIM, a child write will make it transition to Active. + // Because `ptr1` is ReservedIM, a child write will make it transition to Unique. // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it. let x = (*ptr1).get(); *x = 1; diff --git a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs index 4fbccef2367..edd649b91ed 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs @@ -6,7 +6,7 @@ mod utils; // To check that a reborrow is counted as a Read access, we use a reborrow -// with no additional Read to Freeze an Active pointer. +// with no additional Read to Freeze an Unique pointer. fn main() { unsafe { @@ -15,7 +15,7 @@ fn main() { let alloc_id = alloc_id!(parent); let x = &mut *parent; name!(x); - *x = 0; // x is now Active + *x = 0; // x is now Unique print_state!(alloc_id); let y = &mut *parent; name!(y); diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs index c57cd7fcf0a..83e1d9c70ed 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs @@ -68,7 +68,7 @@ unsafe fn cell_unprotected_read() { } // Foreign Write on an interior mutable pointer is a noop. -// Also y must become Active. +// Also y must become Unique. unsafe fn cell_unprotected_write() { print("[interior mut] Foreign Write: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); @@ -97,7 +97,7 @@ unsafe fn int_protected_read() { } // Foreign Read on a Reserved is a noop. -// Also y must become Active. +// Also y must become Unique. unsafe fn int_unprotected_read() { print("[] Foreign Read: Res -> Res"); let base = &mut 0u8; diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs index 138ada4e20d..37f99962163 100644 --- a/src/tools/miri/tests/utils/mod.rs +++ b/src/tools/miri/tests/utils/mod.rs @@ -16,3 +16,53 @@ pub fn run_provenance_gc() { // SAFETY: No preconditions. The GC is fine to run at any time. unsafe { miri_run_provenance_gc() } } + +/// Check that the function produces the intended set of outcomes. +#[track_caller] +pub fn check_all_outcomes<T: Eq + std::hash::Hash + std::fmt::Debug>( + expected: impl IntoIterator<Item = T>, + generate: impl Fn() -> T, +) { + use std::collections::HashSet; + + let expected: HashSet<T> = HashSet::from_iter(expected); + let mut seen = HashSet::new(); + // Let's give it N times as many tries as we are expecting values. + let min_tries = std::cmp::max(20, expected.len() * 4); + let max_tries = expected.len() * 50; + for i in 0..max_tries { + let val = generate(); + assert!(expected.contains(&val), "got an unexpected value: {val:?}"); + seen.insert(val); + if i >= min_tries && expected.len() == seen.len() { + // We saw everything and we did enough tries, let's avoid wasting time. + return; + } + } + // Let's see if we saw them all. + if expected.len() == seen.len() { + return; + } + // Find the missing one. + for val in expected { + if !seen.contains(&val) { + panic!("did not get value that should be possible: {val:?}"); + } + } + unreachable!() +} + +/// Check that the operation is non-deterministic +#[track_caller] +pub fn check_nondet<T: PartialEq + std::fmt::Debug>(f: impl Fn() -> T) { + let rounds = 50; + let first = f(); + for _ in 1..rounds { + if f() != first { + // We saw two different values! + return; + } + } + // We saw the same thing N times. + panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); +} |
