Skip to content

Commit a2323a9

Browse files
committed
add some test cases for overlapping yielded items
These are just some sanity checks to ensure NLLs, the polonius alpha analysis, and the datalog implementation behave the same on these common examples.
1 parent 5a78b67 commit a2323a9

File tree

4 files changed

+153
-0
lines changed

4 files changed

+153
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
2+
--> $DIR/lending-iterator-sanity-checks.rs:19:19
3+
|
4+
LL | fn use_live<T: LendingIterator>(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> {
5+
| - let's call the lifetime of this reference `'1`
6+
LL | let Some(i) = t.next() else { return None };
7+
| - first mutable borrow occurs here
8+
LL | let Some(j) = t.next() else { return None };
9+
| ^ second mutable borrow occurs here
10+
...
11+
LL | Some((i, j))
12+
| ------------ returning this value requires that `*t` is borrowed for `'1`
13+
14+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
15+
--> $DIR/lending-iterator-sanity-checks.rs:31:13
16+
|
17+
LL | let i = t.next();
18+
| - first mutable borrow occurs here
19+
...
20+
LL | let j = t.next();
21+
| ^ second mutable borrow occurs here
22+
LL |
23+
LL | }
24+
| - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<<T as LendingIterator>::Item<'_>>`
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0499`.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
2+
--> $DIR/lending-iterator-sanity-checks.rs:19:19
3+
|
4+
LL | fn use_live<T: LendingIterator>(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> {
5+
| - let's call the lifetime of this reference `'1`
6+
LL | let Some(i) = t.next() else { return None };
7+
| - first mutable borrow occurs here
8+
LL | let Some(j) = t.next() else { return None };
9+
| ^ second mutable borrow occurs here
10+
...
11+
LL | Some((i, j))
12+
| ------------ returning this value requires that `*t` is borrowed for `'1`
13+
14+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
15+
--> $DIR/lending-iterator-sanity-checks.rs:31:13
16+
|
17+
LL | let i = t.next();
18+
| - first mutable borrow occurs here
19+
...
20+
LL | let j = t.next();
21+
| ^ second mutable borrow occurs here
22+
LL |
23+
LL | }
24+
| - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<<T as LendingIterator>::Item<'_>>`
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0499`.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
2+
--> $DIR/lending-iterator-sanity-checks.rs:19:19
3+
|
4+
LL | let Some(i) = t.next() else { return None };
5+
| - first mutable borrow occurs here
6+
LL | let Some(j) = t.next() else { return None };
7+
| ^ second mutable borrow occurs here
8+
...
9+
LL | }
10+
| - first borrow might be used here, when `i` is dropped and runs the destructor for type `<T as LendingIterator>::Item<'_>`
11+
12+
error[E0499]: cannot borrow `*t` as mutable more than once at a time
13+
--> $DIR/lending-iterator-sanity-checks.rs:31:13
14+
|
15+
LL | let i = t.next();
16+
| - first mutable borrow occurs here
17+
...
18+
LL | let j = t.next();
19+
| ^ second mutable borrow occurs here
20+
LL |
21+
LL | }
22+
| - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<<T as LendingIterator>::Item<'_>>`
23+
24+
error: aborting due to 2 previous errors
25+
26+
For more information about this error, try `rustc --explain E0499`.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Some sanity checks for lending iterators with GATs. This is just some non-regression tests
2+
// ensuring the polonius alpha analysis, the datalog implementation, and NLLs agree in these common
3+
// cases of overlapping yielded items.
4+
5+
//@ ignore-compare-mode-polonius (explicit revisions)
6+
//@ revisions: nll polonius legacy
7+
//@ [polonius] compile-flags: -Z polonius=next
8+
//@ [legacy] compile-flags: -Z polonius=legacy
9+
10+
trait LendingIterator {
11+
type Item<'a>
12+
where
13+
Self: 'a;
14+
fn next(&mut self) -> Option<Self::Item<'_>>;
15+
}
16+
17+
fn use_live<T: LendingIterator>(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> {
18+
let Some(i) = t.next() else { return None };
19+
let Some(j) = t.next() else { return None };
20+
//~^ ERROR cannot borrow `*t` as mutable more than once at a time
21+
22+
// `i` is obviously still (use-)live here, but we called `next` again to get `j`.
23+
Some((i, j))
24+
}
25+
26+
fn drop_live<T: LendingIterator>(t: &mut T) {
27+
let i = t.next();
28+
29+
// Now `i` is use-dead here, but we don't know if the iterator items have a `Drop` impl, so it's
30+
// still drop-live.
31+
let j = t.next();
32+
//~^ ERROR cannot borrow `*t` as mutable more than once at a time
33+
}
34+
35+
// But we can still manually serialize the lifetimes with scopes (or preventing the destructor from
36+
// being called), so they're not overlapping.
37+
fn manually_non_overlapping<T: LendingIterator>(t: &mut T) {
38+
{
39+
let i = t.next();
40+
}
41+
42+
let j = t.next(); // i is dead
43+
44+
drop(j);
45+
let k = t.next(); // j is dead
46+
47+
let k = std::mem::ManuallyDrop::new(k);
48+
let l = t.next(); // we told the compiler that k is not drop-live
49+
}
50+
51+
// The cfg below is because there's a diagnostic ICE trying to explain the source of the error when
52+
// using the datalog implementation. We're not fixing *that*, outside of removing the implementation
53+
// in the future.
54+
#[cfg(not(legacy))] // FIXME: remove this cfg when removing the datalog implementation
55+
fn items_have_no_borrows<T: LendingIterator>(t: &mut T)
56+
where
57+
for<'a> T::Item<'a>: 'static,
58+
{
59+
let i = t.next();
60+
let j = t.next();
61+
}
62+
63+
fn items_are_copy<T: LendingIterator>(t: &mut T)
64+
where
65+
for<'a> T::Item<'a>: Copy,
66+
{
67+
let i = t.next();
68+
let j = t.next();
69+
}
70+
71+
fn main() {}

0 commit comments

Comments
 (0)