Skip to content

Commit 46b59a7

Browse files
authored
Unrolled build for #145053
Rollup merge of #145053 - lqd:known-bugs, r=jackh726 Add a lot of NLL `known-bug` tests r? ``@jackh726`` As requested in #143093 (review) this extracts most tests from that PR and expands upon them as described. The handful of linked-list cursor-like tests will also turn into polonius=next known-bugs in #143093 where the behavior w/r/t kills changes of course.
2 parents 67d45f4 + 202963f commit 46b59a7

28 files changed

+1034
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0499]: cannot borrow `self.iter` as mutable more than once at a time
2+
--> $DIR/filtering-lending-iterator-issue-92985.rs:49:32
3+
|
4+
LL | fn next(&mut self) -> Option<I::Item<'_>> {
5+
| - let's call the lifetime of this reference `'1`
6+
LL | while let Some(item) = self.iter.next() {
7+
| ^^^^^^^^^ `self.iter` was mutably borrowed here in the previous iteration of the loop
8+
LL | if (self.predicate)(&item) {
9+
LL | return Some(item);
10+
| ---------- returning this value requires that `self.iter` is borrowed for `'1`
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0499`.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![crate_type = "lib"]
2+
3+
// This test is an example of a filtering lending iterator with GATs from #92985 (that is similar to
4+
// NLL problem case #3) to ensure it "works" with the polonius alpha analysis as with the datalog
5+
// implementation.
6+
//
7+
// The polonius analysis only changes how the `Filter::next` function is borrowcked, not the bounds
8+
// on the predicate from using the GAT. So even if the #92985 limitation is removed, the unrelated
9+
// 'static limitation on the predicate argument is still there, and the pattern is still impractical
10+
// to use in the real world.
11+
12+
//@ ignore-compare-mode-polonius (explicit revisions)
13+
//@ revisions: nll polonius legacy
14+
//@ [nll] known-bug: #92985
15+
//@ [polonius] check-pass
16+
//@ [polonius] compile-flags: -Z polonius=next
17+
//@ [legacy] check-pass
18+
//@ [legacy] compile-flags: -Z polonius=legacy
19+
20+
trait LendingIterator {
21+
type Item<'a>
22+
where
23+
Self: 'a;
24+
fn next(&mut self) -> Option<Self::Item<'_>>;
25+
26+
fn filter<P>(self, predicate: P) -> Filter<Self, P>
27+
where
28+
Self: Sized,
29+
P: FnMut(&Self::Item<'_>) -> bool,
30+
{
31+
Filter { iter: self, predicate }
32+
}
33+
}
34+
35+
pub struct Filter<I, P> {
36+
iter: I,
37+
predicate: P,
38+
}
39+
impl<I: LendingIterator, P> LendingIterator for Filter<I, P>
40+
where
41+
P: FnMut(&I::Item<'_>) -> bool,
42+
{
43+
type Item<'a>
44+
= I::Item<'a>
45+
where
46+
Self: 'a;
47+
48+
fn next(&mut self) -> Option<I::Item<'_>> {
49+
while let Some(item) = self.iter.next() {
50+
if (self.predicate)(&item) {
51+
return Some(item);
52+
}
53+
}
54+
return None;
55+
}
56+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0499]: cannot borrow `*elements` as mutable more than once at a time
2+
--> $DIR/iterating-updating-cursor-issue-108704.rs:40:26
3+
|
4+
LL | for (idx, el) in elements.iter_mut().enumerate() {
5+
| ^^^^^^^^
6+
| |
7+
| `*elements` was mutably borrowed here in the previous iteration of the loop
8+
| first borrow used here, in later iteration of loop
9+
10+
error: aborting due to 1 previous error
11+
12+
For more information about this error, try `rustc --explain E0499`.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![crate_type = "lib"]
2+
3+
// An example from #108704 of the linked-list cursor-like pattern of #46859/#48001.
4+
5+
//@ ignore-compare-mode-polonius (explicit revisions)
6+
//@ revisions: nll polonius legacy
7+
//@ [nll] known-bug: #108704
8+
//@ [polonius] check-pass
9+
//@ [polonius] compile-flags: -Z polonius=next
10+
//@ [legacy] check-pass
11+
//@ [legacy] compile-flags: -Z polonius=legacy
12+
13+
struct Root {
14+
children: Vec<Node>,
15+
}
16+
17+
struct Node {
18+
name: String,
19+
children: Vec<Node>,
20+
}
21+
22+
fn merge_tree_ok(root: &mut Root, path: Vec<String>) {
23+
let mut elements = &mut root.children;
24+
25+
for p in path.iter() {
26+
for (idx, el) in elements.iter_mut().enumerate() {
27+
if el.name == *p {
28+
elements = &mut elements[idx].children;
29+
break;
30+
}
31+
}
32+
}
33+
}
34+
35+
// NLLs fail here
36+
fn merge_tree_ko(root: &mut Root, path: Vec<String>) {
37+
let mut elements = &mut root.children;
38+
39+
for p in path.iter() {
40+
for (idx, el) in elements.iter_mut().enumerate() {
41+
if el.name == *p {
42+
elements = &mut el.children;
43+
break;
44+
}
45+
}
46+
}
47+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0499]: cannot borrow `p.0` as mutable more than once at a time
2+
--> $DIR/iterating-updating-cursor-issue-57165.rs:29:20
3+
|
4+
LL | while let Some(now) = p {
5+
| ^^^ - first borrow used here, in later iteration of loop
6+
| |
7+
| `p.0` was mutably borrowed here in the previous iteration of the loop
8+
9+
error[E0503]: cannot use `*p` because it was mutably borrowed
10+
--> $DIR/iterating-updating-cursor-issue-57165.rs:29:27
11+
|
12+
LL | while let Some(now) = p {
13+
| --- ^
14+
| | |
15+
| | use of borrowed `p.0`
16+
| | borrow later used here
17+
| `p.0` is borrowed here
18+
19+
error: aborting due to 2 previous errors
20+
21+
Some errors have detailed explanations: E0499, E0503.
22+
For more information about an error, try `rustc --explain E0499`.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![crate_type = "lib"]
2+
3+
// An example from #57165 of the linked-list cursor-like pattern of #46859/#48001.
4+
5+
//@ ignore-compare-mode-polonius (explicit revisions)
6+
//@ revisions: nll polonius legacy
7+
//@ [nll] known-bug: #57165
8+
//@ [polonius] check-pass
9+
//@ [polonius] compile-flags: -Z polonius=next
10+
//@ [legacy] check-pass
11+
//@ [legacy] compile-flags: -Z polonius=legacy
12+
13+
struct X {
14+
next: Option<Box<X>>,
15+
}
16+
17+
fn no_control_flow() {
18+
let mut b = Some(Box::new(X { next: None }));
19+
let mut p = &mut b;
20+
while let Some(now) = p {
21+
p = &mut now.next;
22+
}
23+
}
24+
25+
// NLLs fail here
26+
fn conditional() {
27+
let mut b = Some(Box::new(X { next: None }));
28+
let mut p = &mut b;
29+
while let Some(now) = p {
30+
if true {
31+
p = &mut now.next;
32+
}
33+
}
34+
}
35+
36+
fn conditional_with_indirection() {
37+
let mut b = Some(Box::new(X { next: None }));
38+
let mut p = &mut b;
39+
while let Some(now) = p {
40+
if true {
41+
p = &mut p.as_mut().unwrap().next;
42+
}
43+
}
44+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0506]: cannot assign to `*node_ref` because it is borrowed
2+
--> $DIR/iterating-updating-cursor-issue-63908.rs:42:5
3+
|
4+
LL | fn remove_last_node_iterative<T>(mut node_ref: &mut List<T>) {
5+
| - let's call the lifetime of this reference `'1`
6+
LL | loop {
7+
LL | let next_ref = &mut node_ref.as_mut().unwrap().next;
8+
| -------- `*node_ref` is borrowed here
9+
...
10+
LL | node_ref = next_ref;
11+
| ------------------- assignment requires that `*node_ref` is borrowed for `'1`
12+
...
13+
LL | *node_ref = None;
14+
| ^^^^^^^^^ `*node_ref` is assigned to here but it was already borrowed
15+
16+
error: aborting due to 1 previous error
17+
18+
For more information about this error, try `rustc --explain E0506`.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![crate_type = "lib"]
2+
3+
// An example from #63908 of the linked-list cursor-like pattern of #46859/#48001.
4+
5+
//@ ignore-compare-mode-polonius (explicit revisions)
6+
//@ revisions: nll polonius legacy
7+
//@ [nll] known-bug: #63908
8+
//@ [polonius] check-pass
9+
//@ [polonius] compile-flags: -Z polonius=next
10+
//@ [legacy] check-pass
11+
//@ [legacy] compile-flags: -Z polonius=legacy
12+
13+
struct Node<T> {
14+
value: T,
15+
next: Option<Box<Self>>,
16+
}
17+
18+
type List<T> = Option<Box<Node<T>>>;
19+
20+
fn remove_last_node_recursive<T>(node_ref: &mut List<T>) {
21+
let next_ref = &mut node_ref.as_mut().unwrap().next;
22+
23+
if next_ref.is_some() {
24+
remove_last_node_recursive(next_ref);
25+
} else {
26+
*node_ref = None;
27+
}
28+
}
29+
30+
// NLLs fail here
31+
fn remove_last_node_iterative<T>(mut node_ref: &mut List<T>) {
32+
loop {
33+
let next_ref = &mut node_ref.as_mut().unwrap().next;
34+
35+
if next_ref.is_some() {
36+
node_ref = next_ref;
37+
} else {
38+
break;
39+
}
40+
}
41+
42+
*node_ref = None;
43+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0506]: cannot assign to `*opt` because it is borrowed
2+
--> $DIR/nll-problem-case-3-issue-112087.rs:23:5
3+
|
4+
LL | fn issue_112087<'a>(opt: &'a mut Option<i32>, b: bool) -> Result<&'a mut Option<i32>, &'a mut i32> {
5+
| -- lifetime `'a` defined here
6+
LL | if let Some(v) = opt {
7+
| - `*opt` is borrowed here
8+
LL | if b {
9+
LL | return Err(v);
10+
| ------ returning this value requires that `opt.0` is borrowed for `'a`
11+
...
12+
LL | *opt = None;
13+
| ^^^^^^^^^^^ `*opt` is assigned to here but it was already borrowed
14+
15+
error: aborting due to 1 previous error
16+
17+
For more information about this error, try `rustc --explain E0506`.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![crate_type = "lib"]
2+
3+
// This is part of a collection of regression tests related to the NLL problem case 3 that was
4+
// deferred from the implementation of the NLL RFC, and left to be implemented by polonius. They are
5+
// from open issues, e.g. tagged fixed-by-polonius, to ensure that the polonius alpha analysis does
6+
// handle them, as does the datalog implementation.
7+
8+
//@ ignore-compare-mode-polonius (explicit revisions)
9+
//@ revisions: nll polonius legacy
10+
//@ [nll] known-bug: #112087
11+
//@ [polonius] check-pass
12+
//@ [polonius] compile-flags: -Z polonius=next
13+
//@ [legacy] check-pass
14+
//@ [legacy] compile-flags: -Z polonius=legacy
15+
16+
fn issue_112087<'a>(opt: &'a mut Option<i32>, b: bool) -> Result<&'a mut Option<i32>, &'a mut i32> {
17+
if let Some(v) = opt {
18+
if b {
19+
return Err(v);
20+
}
21+
}
22+
23+
*opt = None;
24+
return Ok(opt);
25+
}

0 commit comments

Comments
 (0)