Skip to content

Commit e77e020

Browse files
authored
Rollup merge of #102680 - dtolnay:btreesend, r=thomcc
Fix overconstrained Send impls in btree internals Fixes dtolnay/async-trait#215. Minimal repro: ```rust use std::collections::btree_map::Iter; fn require_send<T: Send>(_: T) {} fn main() { require_send(async { let _iter = None::<Iter<(), &()>>; async {}.await; }); } ``` ```console error: higher-ranked lifetime error --> src/main.rs:6:5 | 6 | / require_send(async { 7 | | let _iter = None::<Iter<(), &()>>; 8 | | async {}.await; 9 | | }); | |______^ | = note: could not prove `impl Future<Output = ()>: Send` ``` Not-quite-so-minimal repro: ```rust use std::collections::BTreeMap; use std::future::Future; fn spawn<T: Future + Send>(_: T) {} async fn f() { let map = BTreeMap::<u32, Box<dyn Send + Sync>>::new(); for _ in &map { async {}.await; } } fn main() { spawn(f()); } ``` ```console error: higher-ranked lifetime error --> src/main.rs:14:5 | 14 | spawn(f()); | ^^^^^^^^^^ | = note: could not prove `impl Future<Output = ()>: Send` ``` I am not familiar with the btree internals, but it seems clear to me that the `async fn f` above should return a Send future. Using HashMap instead of BTreeMap in that code makes it already return a Send future. The _"higher-ranked lifetime error"_ message may be a regression in Rust 1.63. Using older compilers the error message was more detailed: ```console error: implementation of `Send` is not general enough --> src/main.rs:14:5 | 14 | spawn(f()); | ^^^^^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Immut<'0>, u32, Box<(dyn Send + Sync + '1)>, alloc::collections::btree::node::marker::LeafOrInternal>`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Immut<'2>, u32, Box<dyn Send + Sync>, alloc::collections::btree::node::marker::LeafOrInternal>`, for some specific lifetime `'2` error: implementation of `Send` is not general enough --> src/main.rs:14:5 | 14 | spawn(f()); | ^^^^^ implementation of `Send` is not general enough | = note: `Send` would have to be implemented for the type `alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Immut<'0>, u32, Box<(dyn Send + Sync + '1)>, alloc::collections::btree::node::marker::Leaf>`, for any two lifetimes `'0` and `'1`... = note: ...but `Send` is actually implemented for the type `alloc::collections::btree::node::NodeRef<alloc::collections::btree::node::marker::Immut<'2>, u32, Box<dyn Send + Sync>, alloc::collections::btree::node::marker::Leaf>`, for some specific lifetime `'2` ```
2 parents dd0fa6f + 4fdd0d9 commit e77e020

File tree

3 files changed

+300
-3
lines changed

3 files changed

+300
-3
lines changed

library/alloc/src/collections/btree/node.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,9 @@ impl<'a, K: 'a, V: 'a, Type> Clone for NodeRef<marker::Immut<'a>, K, V, Type> {
206206

207207
unsafe impl<BorrowType, K: Sync, V: Sync, Type> Sync for NodeRef<BorrowType, K, V, Type> {}
208208

209-
unsafe impl<'a, K: Sync + 'a, V: Sync + 'a, Type> Send for NodeRef<marker::Immut<'a>, K, V, Type> {}
210-
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::Mut<'a>, K, V, Type> {}
211-
unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
209+
unsafe impl<K: Sync, V: Sync, Type> Send for NodeRef<marker::Immut<'_>, K, V, Type> {}
210+
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Mut<'_>, K, V, Type> {}
211+
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::ValMut<'_>, K, V, Type> {}
212212
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
213213
unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Dying, K, V, Type> {}
214214

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)