Improve diagnostics for buffer reuse with borrowed references
This commit is contained in:
parent
b2ee1b333a
commit
61b26f9f60
7 changed files with 185 additions and 5 deletions
|
|
@ -3084,6 +3084,39 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
});
|
||||
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
|
||||
|
||||
// Detect buffer reuse pattern
|
||||
if let BorrowExplanation::UsedLater(_dropped_local, _, _, _) = explanation {
|
||||
// Check all locals at the borrow location to find Vec<&T> types
|
||||
for (local, local_decl) in self.body.local_decls.iter_enumerated() {
|
||||
if let ty::Adt(adt_def, args) = local_decl.ty.kind()
|
||||
&& self.infcx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())
|
||||
&& args.len() > 0
|
||||
{
|
||||
let vec_inner_ty = args.type_at(0);
|
||||
// Check if Vec contains references
|
||||
if vec_inner_ty.is_ref() {
|
||||
let local_place = local.into();
|
||||
if let Some(local_name) = self.describe_place(local_place) {
|
||||
err.span_label(
|
||||
local_decl.source_info.span,
|
||||
format!("variable `{local_name}` declared here"),
|
||||
);
|
||||
err.note(
|
||||
format!(
|
||||
"`{local_name}` is a collection that stores borrowed references, \
|
||||
but {name} does not live long enough to be stored in it"
|
||||
)
|
||||
);
|
||||
err.help(
|
||||
"buffer reuse with borrowed references requires unsafe code or restructuring"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
|
|
|
|||
63
tests/ui/borrowck/buffer-reuse-pattern-issue-147694.rs
Normal file
63
tests/ui/borrowck/buffer-reuse-pattern-issue-147694.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
fn process_data(_: &[&[u8]]) {}
|
||||
|
||||
fn test_buffer_cleared_after_use() {
|
||||
let sources = vec![vec![1u8, 2, 3, 4, 5], vec![6, 7, 8, 9]];
|
||||
let mut buffer: Vec<&[u8]> = vec![];
|
||||
//~^ NOTE variable `buffer` declared here
|
||||
|
||||
for source in sources {
|
||||
let data: Vec<u8> = source;
|
||||
//~^ NOTE binding `data` declared here
|
||||
buffer.extend(data.split(|x| *x == 3));
|
||||
//~^ ERROR `data` does not live long enough
|
||||
//~| NOTE borrowed value does not live long enough
|
||||
//~| NOTE borrow later used here
|
||||
//~| NOTE `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
//~| HELP buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
process_data(&buffer);
|
||||
buffer.clear();
|
||||
} //~ NOTE `data` dropped here while still borrowed
|
||||
}
|
||||
|
||||
fn test_buffer_cleared_at_start() {
|
||||
let sources = vec![vec![1u8, 2, 3, 4, 5], vec![6, 7, 8, 9]];
|
||||
let mut buffer: Vec<&[u8]> = vec![];
|
||||
//~^ NOTE variable `buffer` declared here
|
||||
|
||||
for source in sources {
|
||||
buffer.clear();
|
||||
//~^ NOTE borrow later used here
|
||||
let data: Vec<u8> = source;
|
||||
//~^ NOTE binding `data` declared here
|
||||
buffer.extend(data.split(|x| *x == 3));
|
||||
//~^ ERROR `data` does not live long enough
|
||||
//~| NOTE borrowed value does not live long enough
|
||||
//~| NOTE `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
//~| HELP buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
process_data(&buffer);
|
||||
} //~ NOTE `data` dropped here while still borrowed
|
||||
}
|
||||
|
||||
fn test_no_explicit_clear() {
|
||||
let sources = vec![vec![1u8, 2, 3, 4, 5], vec![6, 7, 8, 9]];
|
||||
let mut buffer: Vec<&[u8]> = vec![];
|
||||
//~^ NOTE variable `buffer` declared here
|
||||
|
||||
for source in sources {
|
||||
let data: Vec<u8> = source;
|
||||
//~^ NOTE binding `data` declared here
|
||||
buffer.extend(data.split(|x| *x == 3));
|
||||
//~^ ERROR `data` does not live long enough
|
||||
//~| NOTE borrowed value does not live long enough
|
||||
//~| NOTE borrow later used here
|
||||
//~| NOTE `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
//~| HELP buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
process_data(&buffer);
|
||||
} //~ NOTE `data` dropped here while still borrowed
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_buffer_cleared_after_use();
|
||||
test_buffer_cleared_at_start();
|
||||
test_no_explicit_clear();
|
||||
}
|
||||
64
tests/ui/borrowck/buffer-reuse-pattern-issue-147694.stderr
Normal file
64
tests/ui/borrowck/buffer-reuse-pattern-issue-147694.stderr
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
error[E0597]: `data` does not live long enough
|
||||
--> $DIR/buffer-reuse-pattern-issue-147694.rs:11:23
|
||||
|
|
||||
LL | let mut buffer: Vec<&[u8]> = vec![];
|
||||
| ---------- variable `buffer` declared here
|
||||
...
|
||||
LL | let data: Vec<u8> = source;
|
||||
| ---- binding `data` declared here
|
||||
LL |
|
||||
LL | buffer.extend(data.split(|x| *x == 3));
|
||||
| ------ ^^^^ borrowed value does not live long enough
|
||||
| |
|
||||
| borrow later used here
|
||||
...
|
||||
LL | }
|
||||
| - `data` dropped here while still borrowed
|
||||
|
|
||||
= note: `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error[E0597]: `data` does not live long enough
|
||||
--> $DIR/buffer-reuse-pattern-issue-147694.rs:32:23
|
||||
|
|
||||
LL | let mut buffer: Vec<&[u8]> = vec![];
|
||||
| ---------- variable `buffer` declared here
|
||||
...
|
||||
LL | buffer.clear();
|
||||
| ------ borrow later used here
|
||||
LL |
|
||||
LL | let data: Vec<u8> = source;
|
||||
| ---- binding `data` declared here
|
||||
LL |
|
||||
LL | buffer.extend(data.split(|x| *x == 3));
|
||||
| ^^^^ borrowed value does not live long enough
|
||||
...
|
||||
LL | }
|
||||
| - `data` dropped here while still borrowed
|
||||
|
|
||||
= note: `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error[E0597]: `data` does not live long enough
|
||||
--> $DIR/buffer-reuse-pattern-issue-147694.rs:49:23
|
||||
|
|
||||
LL | let mut buffer: Vec<&[u8]> = vec![];
|
||||
| ---------- variable `buffer` declared here
|
||||
...
|
||||
LL | let data: Vec<u8> = source;
|
||||
| ---- binding `data` declared here
|
||||
LL |
|
||||
LL | buffer.extend(data.split(|x| *x == 3));
|
||||
| ------ ^^^^ borrowed value does not live long enough
|
||||
| |
|
||||
| borrow later used here
|
||||
...
|
||||
LL | }
|
||||
| - `data` dropped here while still borrowed
|
||||
|
|
||||
= note: `buffer` is a collection that stores borrowed references, but `data` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
|
|
@ -4,13 +4,18 @@ error[E0597]: `line` does not live long enough
|
|||
LL | for line in vec!["123456789".to_string(), "12345678".to_string()] {
|
||||
| ---- binding `line` declared here
|
||||
LL | let v: Vec<&str> = line.split_whitespace().collect();
|
||||
| ^^^^ borrowed value does not live long enough
|
||||
| - ^^^^ borrowed value does not live long enough
|
||||
| |
|
||||
| variable `v` declared here
|
||||
...
|
||||
LL | acc += cnt2;
|
||||
| --- borrow later used here
|
||||
...
|
||||
LL | }
|
||||
| - `line` dropped here while still borrowed
|
||||
|
|
||||
= note: `v` is a collection that stores borrowed references, but `line` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ fn id<T>(x: T) -> T { x }
|
|||
fn f() {
|
||||
let old = ['o']; // statement 0
|
||||
let mut v1 = Vec::new(); // statement 1
|
||||
//~^ NOTE variable `v1` declared here
|
||||
|
||||
let mut v2 = Vec::new(); // statement 2
|
||||
|
||||
|
|
@ -13,6 +14,8 @@ fn f() {
|
|||
v2.push(&young[0]); // statement 4
|
||||
//~^ ERROR `young[_]` does not live long enough
|
||||
//~| NOTE borrowed value does not live long enough
|
||||
//~| NOTE `v1` is a collection that stores borrowed references, but `young[_]` does not live long enough to be stored in it
|
||||
//~| HELP buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
} //~ NOTE `young[_]` dropped here while still borrowed
|
||||
|
||||
let mut v3 = Vec::new(); // statement 5
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
error[E0597]: `young[_]` does not live long enough
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:13:17
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:14:17
|
||||
|
|
||||
LL | let mut v1 = Vec::new(); // statement 1
|
||||
| ------ variable `v1` declared here
|
||||
...
|
||||
LL | let young = ['y']; // statement 3
|
||||
| ----- binding `young` declared here
|
||||
...
|
||||
|
|
@ -12,9 +15,12 @@ LL | }
|
|||
...
|
||||
LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref();
|
||||
| -- borrow later used here
|
||||
|
|
||||
= note: `v1` is a collection that stores borrowed references, but `young[_]` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:20:14
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:23:14
|
||||
|
|
||||
LL | v3.push(&id('x')); // statement 6
|
||||
| ^^^^^^^ - temporary value is freed at the end of this statement
|
||||
|
|
@ -31,7 +37,7 @@ LL ~ v3.push(&binding); // statement 6
|
|||
|
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:30:18
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:33:18
|
||||
|
|
||||
LL | v4.push(&id('y'));
|
||||
| ^^^^^^^ - temporary value is freed at the end of this statement
|
||||
|
|
@ -44,7 +50,7 @@ LL | v4.use_ref();
|
|||
= note: consider using a `let` binding to create a longer lived value
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:41:14
|
||||
--> $DIR/borrowck-let-suggestion-suffixes.rs:44:14
|
||||
|
|
||||
LL | v5.push(&id('z'));
|
||||
| ^^^^^^^ - temporary value is freed at the end of this statement
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ LL | _y.push(&mut z);
|
|||
error[E0597]: `z` does not live long enough
|
||||
--> $DIR/regions-escape-loop-via-vec.rs:7:17
|
||||
|
|
||||
LL | let mut _y = vec![&mut x];
|
||||
| ------ variable `_y` declared here
|
||||
LL | while x < 10 {
|
||||
LL | let mut z = x;
|
||||
| ----- binding `z` declared here
|
||||
LL | _y.push(&mut z);
|
||||
|
|
@ -32,6 +35,9 @@ LL | _y.push(&mut z);
|
|||
...
|
||||
LL | }
|
||||
| - `z` dropped here while still borrowed
|
||||
|
|
||||
= note: `_y` is a collection that stores borrowed references, but `z` does not live long enough to be stored in it
|
||||
= help: buffer reuse with borrowed references requires unsafe code or restructuring
|
||||
|
||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
||||
--> $DIR/regions-escape-loop-via-vec.rs:9:9
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue