Skip to content

Commit fa86341

Browse files
committed
Add regression test for lifetimes in alloc internals autotraits
Currently pretty much all of the btree_map and btree_set ones fail, as well as linked_list::DrainFilter. error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:38:5 | 38 | / require_send_sync(async { 39 | | let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>; 40 | | async {}.await; 41 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:56:5 | 56 | / require_send_sync(async { 57 | | let _v = None::< 58 | | alloc::collections::btree_map::DrainFilter< 59 | | '_, ... | 65 | | async {}.await; 66 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:68:5 | 68 | / require_send_sync(async { 69 | | let _v = None::<alloc::collections::btree_map::Entry<'_, &u32, &u32>>; 70 | | async {}.await; 71 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:88:5 | 88 | / require_send_sync(async { 89 | | let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>; 90 | | async {}.await; 91 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:93:5 | 93 | / require_send_sync(async { 94 | | let _v = None::<alloc::collections::btree_map::IterMut<'_, &u32, &u32>>; 95 | | async {}.await; 96 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:98:5 | 98 | / require_send_sync(async { 99 | | let _v = None::<alloc::collections::btree_map::Keys<'_, &u32, &u32>>; 100 | | async {}.await; 101 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:103:5 | 103 | / require_send_sync(async { 104 | | let _v = None::<alloc::collections::btree_map::OccupiedEntry<'_, &u32, &u32>>; 105 | | async {}.await; 106 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:108:5 | 108 | / require_send_sync(async { 109 | | let _v = None::<alloc::collections::btree_map::OccupiedError<'_, &u32, &u32>>; 110 | | async {}.await; 111 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:113:5 | 113 | / require_send_sync(async { 114 | | let _v = None::<alloc::collections::btree_map::Range<'_, &u32, &u32>>; 115 | | async {}.await; 116 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:118:5 | 118 | / require_send_sync(async { 119 | | let _v = None::<alloc::collections::btree_map::RangeMut<'_, &u32, &u32>>; 120 | | async {}.await; 121 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:123:5 | 123 | / require_send_sync(async { 124 | | let _v = None::<alloc::collections::btree_map::VacantEntry<'_, &u32, &u32>>; 125 | | async {}.await; 126 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:128:5 | 128 | / require_send_sync(async { 129 | | let _v = None::<alloc::collections::btree_map::Values<'_, &u32, &u32>>; 130 | | async {}.await; 131 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:133:5 | 133 | / require_send_sync(async { 134 | | let _v = None::<alloc::collections::btree_map::ValuesMut<'_, &u32, &u32>>; 135 | | async {}.await; 136 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:146:5 | 146 | / require_send_sync(async { 147 | | let _v = None::<alloc::collections::btree_set::Difference<'_, &u32>>; 148 | | async {}.await; 149 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: implementation of `Send` is not general enough --> library/alloc/tests/autotraits.rs:151:5 | 151 | / require_send_sync(async { 152 | | let _v = None::<alloc::collections::btree_set::DrainFilter<'_, &u32, fn(&&u32) -> bool>>; 153 | | async {}.await; 154 | | }); | |______^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `&'0 u32`, for any lifetime `'0`... = note: ...but `Send` is actually implemented for the type `&'1 u32`, for some specific lifetime `'1` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:156:5 | 156 | / require_send_sync(async { 157 | | let _v = None::<alloc::collections::btree_set::Intersection<'_, &u32>>; 158 | | async {}.await; 159 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:166:5 | 166 | / require_send_sync(async { 167 | | let _v = None::<alloc::collections::btree_set::Iter<'_, &u32>>; 168 | | async {}.await; 169 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:171:5 | 171 | / require_send_sync(async { 172 | | let _v = None::<alloc::collections::btree_set::Range<'_, &u32>>; 173 | | async {}.await; 174 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:176:5 | 176 | / require_send_sync(async { 177 | | let _v = None::<alloc::collections::btree_set::SymmetricDifference<'_, &u32>>; 178 | | async {}.await; 179 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:181:5 | 181 | / require_send_sync(async { 182 | | let _v = None::<alloc::collections::btree_set::Union<'_, &u32>>; 183 | | async {}.await; 184 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` error: future cannot be sent between threads safely --> library/alloc/tests/autotraits.rs:243:23 | 243 | require_send_sync(async { | _______________________^ 244 | | let _v = 245 | | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>; 246 | | async {}.await; 247 | | }); | |_____^ future created by async block is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NonNull<std::collections::linked_list::Node<&u32>>` note: future is not `Send` as this value is used across an await --> library/alloc/tests/autotraits.rs:246:17 | 244 | let _v = | -- has type `Option<std::collections::linked_list::DrainFilter<'_, &u32, for<'a, 'b> fn(&'a mut &'b u32) -> bool>>` which is not `Send` 245 | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>; 246 | async {}.await; | ^^^^^^ await occurs here, with `_v` maybe used later 247 | }); | - `_v` is later dropped here note: required by a bound in `require_send_sync` --> library/alloc/tests/autotraits.rs:3:25 | 3 | fn require_send_sync<T: Send + Sync>(_: T) {} | ^^^^ required by this bound in `require_send_sync` error: future cannot be shared between threads safely --> library/alloc/tests/autotraits.rs:243:23 | 243 | require_send_sync(async { | _______________________^ 244 | | let _v = 245 | | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>; 246 | | async {}.await; 247 | | }); | |_____^ future created by async block is not `Sync` | = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `NonNull<std::collections::linked_list::Node<&u32>>` note: future is not `Sync` as this value is used across an await --> library/alloc/tests/autotraits.rs:246:17 | 244 | let _v = | -- has type `Option<std::collections::linked_list::DrainFilter<'_, &u32, for<'a, 'b> fn(&'a mut &'b u32) -> bool>>` which is not `Sync` 245 | None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>; 246 | async {}.await; | ^^^^^^ await occurs here, with `_v` maybe used later 247 | }); | - `_v` is later dropped here note: required by a bound in `require_send_sync` --> library/alloc/tests/autotraits.rs:3:32 | 3 | fn require_send_sync<T: Send + Sync>(_: T) {} | ^^^^ required by this bound in `require_send_sync`
1 parent 01af504 commit fa86341

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed

library/alloc/tests/autotraits.rs

+293
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
fn require_sync<T: Sync>(_: T) {}
2+
fn require_send_sync<T: Send + Sync>(_: T) {}
3+
4+
struct NotSend(*const ());
5+
unsafe impl Sync for NotSend {}
6+
7+
#[test]
8+
fn test_btree_map() {
9+
// Tests of this form are prone to https://github.com/rust-lang/rust/issues/64552.
10+
//
11+
// In theory the async block's future would be Send if the value we hold
12+
// across the await point is Send, and Sync if the value we hold across the
13+
// await point is Sync.
14+
//
15+
// We test autotraits in this convoluted way, instead of a straightforward
16+
// `require_send_sync::<TypeIWantToTest>()`, because the interaction with
17+
// generators exposes some current limitations in rustc's ability to prove a
18+
// lifetime bound on the erased generator witness types. See the above link.
19+
//
20+
// A typical way this would surface in real code is:
21+
//
22+
// fn spawn<T: Future + Send>(_: T) {}
23+
//
24+
// async fn f() {
25+
// let map = BTreeMap::<u32, Box<dyn Send + Sync>>::new();
26+
// for _ in &map {
27+
// async {}.await;
28+
// }
29+
// }
30+
//
31+
// fn main() {
32+
// spawn(f());
33+
// }
34+
//
35+
// where with some unintentionally overconstrained Send impls in liballoc's
36+
// internals, the future might incorrectly not be Send even though every
37+
// single type involved in the program is Send and Sync.
38+
require_send_sync(async {
39+
let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>;
40+
async {}.await;
41+
});
42+
43+
// Testing like this would not catch all issues that the above form catches.
44+
require_send_sync(None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>);
45+
46+
require_sync(async {
47+
let _v = None::<alloc::collections::btree_map::Iter<'_, u32, NotSend>>;
48+
async {}.await;
49+
});
50+
51+
require_send_sync(async {
52+
let _v = None::<alloc::collections::btree_map::BTreeMap<&u32, &u32>>;
53+
async {}.await;
54+
});
55+
56+
require_send_sync(async {
57+
let _v = None::<
58+
alloc::collections::btree_map::DrainFilter<
59+
'_,
60+
&u32,
61+
&u32,
62+
fn(&&u32, &mut &u32) -> bool,
63+
>,
64+
>;
65+
async {}.await;
66+
});
67+
68+
require_send_sync(async {
69+
let _v = None::<alloc::collections::btree_map::Entry<'_, &u32, &u32>>;
70+
async {}.await;
71+
});
72+
73+
require_send_sync(async {
74+
let _v = None::<alloc::collections::btree_map::IntoIter<&u32, &u32>>;
75+
async {}.await;
76+
});
77+
78+
require_send_sync(async {
79+
let _v = None::<alloc::collections::btree_map::IntoKeys<&u32, &u32>>;
80+
async {}.await;
81+
});
82+
83+
require_send_sync(async {
84+
let _v = None::<alloc::collections::btree_map::IntoValues<&u32, &u32>>;
85+
async {}.await;
86+
});
87+
88+
require_send_sync(async {
89+
let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>;
90+
async {}.await;
91+
});
92+
93+
require_send_sync(async {
94+
let _v = None::<alloc::collections::btree_map::IterMut<'_, &u32, &u32>>;
95+
async {}.await;
96+
});
97+
98+
require_send_sync(async {
99+
let _v = None::<alloc::collections::btree_map::Keys<'_, &u32, &u32>>;
100+
async {}.await;
101+
});
102+
103+
require_send_sync(async {
104+
let _v = None::<alloc::collections::btree_map::OccupiedEntry<'_, &u32, &u32>>;
105+
async {}.await;
106+
});
107+
108+
require_send_sync(async {
109+
let _v = None::<alloc::collections::btree_map::OccupiedError<'_, &u32, &u32>>;
110+
async {}.await;
111+
});
112+
113+
require_send_sync(async {
114+
let _v = None::<alloc::collections::btree_map::Range<'_, &u32, &u32>>;
115+
async {}.await;
116+
});
117+
118+
require_send_sync(async {
119+
let _v = None::<alloc::collections::btree_map::RangeMut<'_, &u32, &u32>>;
120+
async {}.await;
121+
});
122+
123+
require_send_sync(async {
124+
let _v = None::<alloc::collections::btree_map::VacantEntry<'_, &u32, &u32>>;
125+
async {}.await;
126+
});
127+
128+
require_send_sync(async {
129+
let _v = None::<alloc::collections::btree_map::Values<'_, &u32, &u32>>;
130+
async {}.await;
131+
});
132+
133+
require_send_sync(async {
134+
let _v = None::<alloc::collections::btree_map::ValuesMut<'_, &u32, &u32>>;
135+
async {}.await;
136+
});
137+
}
138+
139+
#[test]
140+
fn test_btree_set() {
141+
require_send_sync(async {
142+
let _v = None::<alloc::collections::btree_set::BTreeSet<&u32>>;
143+
async {}.await;
144+
});
145+
146+
require_send_sync(async {
147+
let _v = None::<alloc::collections::btree_set::Difference<'_, &u32>>;
148+
async {}.await;
149+
});
150+
151+
require_send_sync(async {
152+
let _v = None::<alloc::collections::btree_set::DrainFilter<'_, &u32, fn(&&u32) -> bool>>;
153+
async {}.await;
154+
});
155+
156+
require_send_sync(async {
157+
let _v = None::<alloc::collections::btree_set::Intersection<'_, &u32>>;
158+
async {}.await;
159+
});
160+
161+
require_send_sync(async {
162+
let _v = None::<alloc::collections::btree_set::IntoIter<&u32>>;
163+
async {}.await;
164+
});
165+
166+
require_send_sync(async {
167+
let _v = None::<alloc::collections::btree_set::Iter<'_, &u32>>;
168+
async {}.await;
169+
});
170+
171+
require_send_sync(async {
172+
let _v = None::<alloc::collections::btree_set::Range<'_, &u32>>;
173+
async {}.await;
174+
});
175+
176+
require_send_sync(async {
177+
let _v = None::<alloc::collections::btree_set::SymmetricDifference<'_, &u32>>;
178+
async {}.await;
179+
});
180+
181+
require_send_sync(async {
182+
let _v = None::<alloc::collections::btree_set::Union<'_, &u32>>;
183+
async {}.await;
184+
});
185+
}
186+
187+
#[test]
188+
fn test_binary_heap() {
189+
require_send_sync(async {
190+
let _v = None::<alloc::collections::binary_heap::BinaryHeap<&u32>>;
191+
async {}.await;
192+
});
193+
194+
require_send_sync(async {
195+
let _v = None::<alloc::collections::binary_heap::Drain<'_, &u32>>;
196+
async {}.await;
197+
});
198+
199+
require_send_sync(async {
200+
let _v = None::<alloc::collections::binary_heap::DrainSorted<'_, &u32>>;
201+
async {}.await;
202+
});
203+
204+
require_send_sync(async {
205+
let _v = None::<alloc::collections::binary_heap::IntoIter<&u32>>;
206+
async {}.await;
207+
});
208+
209+
require_send_sync(async {
210+
let _v = None::<alloc::collections::binary_heap::IntoIterSorted<&u32>>;
211+
async {}.await;
212+
});
213+
214+
require_send_sync(async {
215+
let _v = None::<alloc::collections::binary_heap::Iter<'_, &u32>>;
216+
async {}.await;
217+
});
218+
219+
require_send_sync(async {
220+
let _v = None::<alloc::collections::binary_heap::PeekMut<'_, &u32>>;
221+
async {}.await;
222+
});
223+
}
224+
225+
#[test]
226+
fn test_linked_list() {
227+
require_send_sync(async {
228+
let _v = None::<alloc::collections::linked_list::Cursor<'_, &u32>>;
229+
async {}.await;
230+
});
231+
232+
require_send_sync(async {
233+
let _v = None::<alloc::collections::linked_list::CursorMut<'_, &u32>>;
234+
async {}.await;
235+
});
236+
237+
// FIXME
238+
/*
239+
require_send_sync(async {
240+
let _v =
241+
None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>;
242+
async {}.await;
243+
});
244+
*/
245+
246+
require_send_sync(async {
247+
let _v = None::<alloc::collections::linked_list::IntoIter<&u32>>;
248+
async {}.await;
249+
});
250+
251+
require_send_sync(async {
252+
let _v = None::<alloc::collections::linked_list::Iter<'_, &u32>>;
253+
async {}.await;
254+
});
255+
256+
require_send_sync(async {
257+
let _v = None::<alloc::collections::linked_list::IterMut<'_, &u32>>;
258+
async {}.await;
259+
});
260+
261+
require_send_sync(async {
262+
let _v = None::<alloc::collections::linked_list::LinkedList<&u32>>;
263+
async {}.await;
264+
});
265+
}
266+
267+
#[test]
268+
fn test_vec_deque() {
269+
require_send_sync(async {
270+
let _v = None::<alloc::collections::vec_deque::Drain<'_, &u32>>;
271+
async {}.await;
272+
});
273+
274+
require_send_sync(async {
275+
let _v = None::<alloc::collections::vec_deque::IntoIter<&u32>>;
276+
async {}.await;
277+
});
278+
279+
require_send_sync(async {
280+
let _v = None::<alloc::collections::vec_deque::Iter<'_, &u32>>;
281+
async {}.await;
282+
});
283+
284+
require_send_sync(async {
285+
let _v = None::<alloc::collections::vec_deque::IterMut<'_, &u32>>;
286+
async {}.await;
287+
});
288+
289+
require_send_sync(async {
290+
let _v = None::<alloc::collections::vec_deque::VecDeque<&u32>>;
291+
async {}.await;
292+
});
293+
}

library/alloc/tests/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(alloc_layout_extra)]
33
#![feature(assert_matches)]
44
#![feature(box_syntax)]
5+
#![feature(btree_drain_filter)]
56
#![feature(cow_is_borrowed)]
67
#![feature(const_box)]
78
#![feature(const_convert)]
@@ -14,6 +15,8 @@
1415
#![feature(core_intrinsics)]
1516
#![feature(drain_filter)]
1617
#![feature(exact_size_is_empty)]
18+
#![feature(linked_list_cursors)]
19+
#![feature(map_try_insert)]
1720
#![feature(new_uninit)]
1821
#![feature(pattern)]
1922
#![feature(trusted_len)]
@@ -49,6 +52,7 @@ use std::collections::hash_map::DefaultHasher;
4952
use std::hash::{Hash, Hasher};
5053

5154
mod arc;
55+
mod autotraits;
5256
mod borrow;
5357
mod boxed;
5458
mod btree_set_hash;

0 commit comments

Comments
 (0)