-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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` ```
- Loading branch information
Showing
3 changed files
with
300 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,293 @@ | ||
fn require_sync<T: Sync>(_: T) {} | ||
fn require_send_sync<T: Send + Sync>(_: T) {} | ||
|
||
struct NotSend(*const ()); | ||
unsafe impl Sync for NotSend {} | ||
|
||
#[test] | ||
fn test_btree_map() { | ||
// Tests of this form are prone to https://github.com/rust-lang/rust/issues/64552. | ||
// | ||
// In theory the async block's future would be Send if the value we hold | ||
// across the await point is Send, and Sync if the value we hold across the | ||
// await point is Sync. | ||
// | ||
// We test autotraits in this convoluted way, instead of a straightforward | ||
// `require_send_sync::<TypeIWantToTest>()`, because the interaction with | ||
// generators exposes some current limitations in rustc's ability to prove a | ||
// lifetime bound on the erased generator witness types. See the above link. | ||
// | ||
// A typical way this would surface in real code is: | ||
// | ||
// 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()); | ||
// } | ||
// | ||
// where with some unintentionally overconstrained Send impls in liballoc's | ||
// internals, the future might incorrectly not be Send even though every | ||
// single type involved in the program is Send and Sync. | ||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
// Testing like this would not catch all issues that the above form catches. | ||
require_send_sync(None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>); | ||
|
||
require_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Iter<'_, u32, NotSend>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::BTreeMap<&u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::< | ||
alloc::collections::btree_map::DrainFilter< | ||
'_, | ||
&u32, | ||
&u32, | ||
fn(&&u32, &mut &u32) -> bool, | ||
>, | ||
>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Entry<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::IntoIter<&u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::IntoKeys<&u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::IntoValues<&u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Iter<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::IterMut<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Keys<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::OccupiedEntry<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::OccupiedError<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Range<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::RangeMut<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::VacantEntry<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::Values<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_map::ValuesMut<'_, &u32, &u32>>; | ||
async {}.await; | ||
}); | ||
} | ||
|
||
#[test] | ||
fn test_btree_set() { | ||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::BTreeSet<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::Difference<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::DrainFilter<'_, &u32, fn(&&u32) -> bool>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::Intersection<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::IntoIter<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::Iter<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::Range<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::SymmetricDifference<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::btree_set::Union<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
} | ||
|
||
#[test] | ||
fn test_binary_heap() { | ||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::BinaryHeap<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::Drain<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::DrainSorted<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::IntoIter<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::IntoIterSorted<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::Iter<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::binary_heap::PeekMut<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
} | ||
|
||
#[test] | ||
fn test_linked_list() { | ||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::Cursor<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::CursorMut<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
// FIXME | ||
/* | ||
require_send_sync(async { | ||
let _v = | ||
None::<alloc::collections::linked_list::DrainFilter<'_, &u32, fn(&mut &u32) -> bool>>; | ||
async {}.await; | ||
}); | ||
*/ | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::IntoIter<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::Iter<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::IterMut<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::linked_list::LinkedList<&u32>>; | ||
async {}.await; | ||
}); | ||
} | ||
|
||
#[test] | ||
fn test_vec_deque() { | ||
require_send_sync(async { | ||
let _v = None::<alloc::collections::vec_deque::Drain<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::vec_deque::IntoIter<&u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::vec_deque::Iter<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::vec_deque::IterMut<'_, &u32>>; | ||
async {}.await; | ||
}); | ||
|
||
require_send_sync(async { | ||
let _v = None::<alloc::collections::vec_deque::VecDeque<&u32>>; | ||
async {}.await; | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters