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`
This commit is contained in:
David Tolnay 2022-10-05 11:23:14 -07:00
parent 01af5040fd
commit fa863414fe
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
2 changed files with 297 additions and 0 deletions

View File

@ -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;
});
}

View File

@ -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::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
mod arc;
mod autotraits;
mod borrow;
mod boxed;
mod btree_set_hash;