Skip to content

Commit f4a1d4b

Browse files
committed
Some local unit tests to track progress and capture interesting cases as I identify them.
issue-62958-c.rs was reduced from the tracing-attributes proc-macro crate. issue-62958-d.rs was reduced from the doc test attached to `AtomicPtr::from_mut_slice`. issue-62958-e.rs covers some important operational characteristics.
1 parent 6dbe78d commit f4a1d4b

File tree

5 files changed

+220
-0
lines changed

5 files changed

+220
-0
lines changed

tests/ui/mir/issue-62958-a.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// revisions: both_off just_prop both_on
2+
// ignore-tidy-linelength
3+
// run-pass
4+
// [both_off] compile-flags: -Z mir-enable-passes=-UpvarToLocalProp,-InlineFutureIntoFuture
5+
// [just_prop] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,-InlineFutureIntoFuture
6+
// [both_on] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,+InlineFutureIntoFuture
7+
// edition:2018
8+
9+
async fn wait() {}
10+
#[allow(dropping_copy_types)]
11+
async fn test(arg: [u8; 8192]) {
12+
wait().await;
13+
drop(arg);
14+
}
15+
16+
#[cfg(both_off)]
17+
fn main() {
18+
let expected = 16000..=17000;
19+
let actual = std::mem::size_of_val(&test([0; 8192]));
20+
assert!(expected.contains(&actual));
21+
}
22+
23+
#[cfg(any(just_prop, both_on))]
24+
fn main() {
25+
let expected = 8192..=9999;
26+
let actual = std::mem::size_of_val(&test([0; 8192]));
27+
assert!(expected.contains(&actual));
28+
}

tests/ui/mir/issue-62958-b.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// revisions: both_off just_prop both_on
2+
// ignore-tidy-linelength
3+
// run-pass
4+
// [both_off] compile-flags: -Z mir-enable-passes=-UpvarToLocalProp,-InlineFutureIntoFuture
5+
// [just_prop] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,-InlineFutureIntoFuture
6+
// [both_on] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,+InlineFutureIntoFuture
7+
// edition:2018
8+
9+
async fn test(_arg: [u8; 8192]) {}
10+
11+
async fn use_future(fut: impl std::future::Future<Output = ()>) {
12+
fut.await
13+
}
14+
15+
#[cfg(both_on)]
16+
fn main() {
17+
let expected = 8192..=9999;
18+
let actual = std::mem::size_of_val(&use_future(use_future(use_future(test([0; 8192])))));
19+
assert!(expected.contains(&actual), "expected: {:?} actual: {}", expected, actual);
20+
}
21+
22+
#[cfg(any(both_off, just_prop))]
23+
fn main() {
24+
let expected = 16000..=8192*(2*2*2*2); // O(2^n) LOL
25+
let actual = std::mem::size_of_val(&use_future(use_future(use_future(test([0; 8192])))));
26+
assert!(expected.contains(&actual), "expected: {:?} actual: {}", expected, actual);
27+
}

tests/ui/mir/issue-62958-c.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// revisions: both_off just_prop both_on
2+
// ignore-tidy-linelength
3+
// build-pass
4+
// [both_off] compile-flags: -Z mir-enable-passes=-UpvarToLocalProp,-InlineFutureIntoFuture
5+
// [just_prop] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,-InlineFutureIntoFuture
6+
// [both_on] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,+InlineFutureIntoFuture
7+
8+
#![crate_type="rlib"]
9+
10+
// FIXME: I should be able to expand the below into something that actually does
11+
// some interesting work. The crucial thing is to enforce a rule that we never
12+
// replace `_3` with `_1.0` on a place that holds a Deref.
13+
14+
pub struct G { p: () }
15+
pub struct S { g: G }
16+
pub struct R<'a> { s: &'a S, b: () }
17+
18+
pub fn gen_function(input: R<'_>) {
19+
let R { s, b: _b } = input;
20+
let S { g, .. } = s;
21+
let G { p: _p, .. } = g;
22+
loop { }
23+
}

tests/ui/mir/issue-62958-d.rs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// revisions: both_off just_prop both_on
2+
// ignore-tidy-linelength
3+
// run-pass
4+
// [both_off] compile-flags: -Z mir-enable-passes=-UpvarToLocalProp,-InlineFutureIntoFuture
5+
// [just_prop] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,-InlineFutureIntoFuture
6+
// [both_on] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,+InlineFutureIntoFuture
7+
// edition:2018
8+
9+
#![feature(atomic_from_mut)]
10+
11+
// FIXME: I should be able to reduce the below further now that I understand the
12+
// nature of the problem. (Namely, the fact that the old upvar_to_local_prop
13+
// code was ignoring locals in projections.)
14+
15+
use std::ptr::null_mut;
16+
use std::sync::atomic::{AtomicPtr, Ordering};
17+
18+
fn main() {
19+
let mut some_ptrs = [null_mut::<String>(); 10];
20+
let a = &*AtomicPtr::from_mut_slice(&mut some_ptrs);
21+
std::thread::scope(|s| {
22+
for i in 0..a.len() {
23+
s.spawn(move || {
24+
let name = Box::new(format!("thread{i}"));
25+
a[i].store(Box::into_raw(name), Ordering::Relaxed);
26+
});
27+
}
28+
});
29+
for p in some_ptrs {
30+
assert!(!p.is_null());
31+
let name = unsafe { Box::from_raw(p) };
32+
println!("Hello, {name}!");
33+
}
34+
}

tests/ui/mir/issue-62958-e.rs

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// revisions: both_off both_on
2+
// ignore-tidy-linelength
3+
// run-pass
4+
// [both_off] compile-flags: -Z mir-enable-passes=-UpvarToLocalProp,-InlineFutureIntoFuture
5+
// [both_on] compile-flags: -Z mir-enable-passes=+UpvarToLocalProp,+InlineFutureIntoFuture
6+
// edition:2018
7+
8+
use std::future::Future;
9+
10+
async fn wait() {}
11+
12+
fn test_shrinks_1(arg: [u8; 1000]) -> impl std::future::Future<Output=()> {
13+
async move {
14+
let mut local = arg;
15+
local[2] = 3;
16+
wait().await;
17+
assert_eq!(local[2], 3);
18+
}
19+
}
20+
21+
fn test_noshrinks_1(mut arg: [u8; 1000]) -> impl std::future::Future<Output=()> {
22+
async move {
23+
let mut local = arg;
24+
local[2] = 3;
25+
let l2 = &mut arg;
26+
l2[2] = 4;
27+
wait().await;
28+
assert_eq!(local[2], 3);
29+
assert_eq!(l2[2], 4);
30+
}
31+
}
32+
33+
fn test_noshrinks_2(arg: [u8; 1000]) -> impl std::future::Future<Output=()> {
34+
async move {
35+
let mut local = arg;
36+
local[2] = 1;
37+
let l2 = arg;
38+
wait().await;
39+
assert_eq!(local[2], 1);
40+
assert_eq!(l2[2], 0);
41+
}
42+
}
43+
44+
fn test_noshrinks_3(arg: [u8; 1000]) -> impl std::future::Future<Output=()> {
45+
async move {
46+
let bor = &arg[2];
47+
let mut local = arg;
48+
local[2] = 1;
49+
wait().await;
50+
assert_eq!(local[2], 1);
51+
assert_eq!(*bor, 0);
52+
}
53+
}
54+
55+
#[cfg(both_on)]
56+
fn check_shrinks(which: &str, fut: impl std::future::Future<Output=()>) {
57+
let sz = std::mem::size_of_val(&fut);
58+
println!("{which}: {sz}");
59+
assert!((1000..=1500).contains(&sz));
60+
run_fut(fut)
61+
}
62+
63+
fn check_no_shrinks(which: &str, fut: impl std::future::Future<Output=()>) {
64+
let sz = std::mem::size_of_val(&fut);
65+
println!("{which}: {sz}");
66+
assert!((2000..).contains(&sz));
67+
run_fut(fut);
68+
}
69+
70+
#[cfg(both_on)]
71+
fn main() {
72+
check_shrinks("s1", test_shrinks_1([0; 1000]));
73+
74+
check_no_shrinks("n1", test_noshrinks_1([0; 1000]));
75+
check_no_shrinks("n2", test_noshrinks_2([0; 1000]));
76+
check_no_shrinks("n3", test_noshrinks_3([0; 1000]));
77+
}
78+
79+
#[cfg(both_off)]
80+
fn main() {
81+
check_no_shrinks("s1", test_shrinks_1([0; 1000]));
82+
check_no_shrinks("n1", test_noshrinks_1([0; 1000]));
83+
check_no_shrinks("n2", test_noshrinks_2([0; 1000]));
84+
check_no_shrinks("n3", test_noshrinks_3([0; 1000]));
85+
}
86+
87+
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
88+
use std::sync::Arc;
89+
use std::task::{Context, Poll, Wake, Waker};
90+
91+
struct MyWaker;
92+
impl Wake for MyWaker {
93+
fn wake(self: Arc<Self>) {
94+
unimplemented!()
95+
}
96+
}
97+
98+
let waker = Waker::from(Arc::new(MyWaker));
99+
let mut context = Context::from_waker(&waker);
100+
101+
let mut pinned = Box::pin(fut);
102+
loop {
103+
match pinned.as_mut().poll(&mut context) {
104+
Poll::Pending => continue,
105+
Poll::Ready(v) => return v,
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)