From fa863414fe1f225f795c6167b12663031ef2a83a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 5 Oct 2022 11:23:14 -0700 Subject: [PATCH 1/2] 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::>; 40 | | async {}.await; 41 | | }); | |______^ | = note: could not prove `impl Future: 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::>; 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::>; 90 | | async {}.await; 91 | | }); | |______^ | = note: could not prove `impl Future: 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::>; 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::>; 100 | | async {}.await; 101 | | }); | |______^ | = note: could not prove `impl Future: 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::>; 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::>; 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::>; 115 | | async {}.await; 116 | | }); | |______^ | = note: could not prove `impl Future: 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::>; 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::>; 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::>; 130 | | async {}.await; 131 | | }); | |______^ | = note: could not prove `impl Future: 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::>; 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::>; 148 | | async {}.await; 149 | | }); | |______^ | = note: could not prove `impl Future: 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:: 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::>; 158 | | async {}.await; 159 | | }); | |______^ | = note: could not prove `impl Future: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:166:5 | 166 | / require_send_sync(async { 167 | | let _v = None::>; 168 | | async {}.await; 169 | | }); | |______^ | = note: could not prove `impl Future: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:171:5 | 171 | / require_send_sync(async { 172 | | let _v = None::>; 173 | | async {}.await; 174 | | }); | |______^ | = note: could not prove `impl Future: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:176:5 | 176 | / require_send_sync(async { 177 | | let _v = None::>; 178 | | async {}.await; 179 | | }); | |______^ | = note: could not prove `impl Future: Send` error: higher-ranked lifetime error --> library/alloc/tests/autotraits.rs:181:5 | 181 | / require_send_sync(async { 182 | | let _v = None::>; 183 | | async {}.await; 184 | | }); | |______^ | = note: could not prove `impl Future: 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:: bool>>; 246 | | async {}.await; 247 | | }); | |_____^ future created by async block is not `Send` | = help: within `impl Future`, the trait `Send` is not implemented for `NonNull>` 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 fn(&'a mut &'b u32) -> bool>>` which is not `Send` 245 | None:: 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) {} | ^^^^ 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:: bool>>; 246 | | async {}.await; 247 | | }); | |_____^ future created by async block is not `Sync` | = help: within `impl Future`, the trait `Sync` is not implemented for `NonNull>` 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 fn(&'a mut &'b u32) -> bool>>` which is not `Sync` 245 | None:: 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) {} | ^^^^ required by this bound in `require_send_sync` --- library/alloc/tests/autotraits.rs | 293 ++++++++++++++++++++++++++++++ library/alloc/tests/lib.rs | 4 + 2 files changed, 297 insertions(+) create mode 100644 library/alloc/tests/autotraits.rs diff --git a/library/alloc/tests/autotraits.rs b/library/alloc/tests/autotraits.rs new file mode 100644 index 00000000000..8ff5f0abe73 --- /dev/null +++ b/library/alloc/tests/autotraits.rs @@ -0,0 +1,293 @@ +fn require_sync(_: T) {} +fn require_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::()`, 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) {} + // + // async fn f() { + // let map = BTreeMap::>::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::>; + async {}.await; + }); + + // Testing like this would not catch all issues that the above form catches. + require_send_sync(None::>); + + require_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + 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::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_btree_set() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None:: bool>>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_binary_heap() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_linked_list() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + // FIXME + /* + require_send_sync(async { + let _v = + None:: bool>>; + async {}.await; + }); + */ + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} + +#[test] +fn test_vec_deque() { + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); + + require_send_sync(async { + let _v = None::>; + async {}.await; + }); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f30ebd77e24..ffc5ca7a5c6 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -2,6 +2,7 @@ #![feature(alloc_layout_extra)] #![feature(assert_matches)] #![feature(box_syntax)] +#![feature(btree_drain_filter)] #![feature(cow_is_borrowed)] #![feature(const_box)] #![feature(const_convert)] @@ -14,6 +15,8 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] +#![feature(linked_list_cursors)] +#![feature(map_try_insert)] #![feature(new_uninit)] #![feature(pattern)] #![feature(trusted_len)] @@ -49,6 +52,7 @@ use std::hash::{Hash, Hasher}; mod arc; +mod autotraits; mod borrow; mod boxed; mod btree_set_hash; From 4fdd0d96757d1ba4bbba0edeff3c8665f324505b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 5 Oct 2022 11:46:12 -0700 Subject: [PATCH 2/2] Fix overconstrained Send impls in btree internals --- library/alloc/src/collections/btree/node.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index f1d2d3b30d9..da766b67a32 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -206,9 +206,9 @@ fn clone(&self) -> Self { unsafe impl Sync for NodeRef {} -unsafe impl<'a, K: Sync + 'a, V: Sync + 'a, Type> Send for NodeRef, K, V, Type> {} -unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} -unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} +unsafe impl Send for NodeRef, K, V, Type> {} +unsafe impl Send for NodeRef, K, V, Type> {} +unsafe impl Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} unsafe impl Send for NodeRef {}