Skip to content

Commit 202963f

Browse files
committed
add multiple known-bugs for the linked-list cursor-like pattern of 46859/48001
these are fixed by polonius=legacy, are currently accepted by polonius=next but won't be by the alpha analysis
1 parent e3aae61 commit 202963f

6 files changed

+186
-0
lines changed
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+
}

0 commit comments

Comments
 (0)