diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 47a1ad0d9489a..133822cdd34d0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -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 diff --git a/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.rs b/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.rs new file mode 100644 index 0000000000000..c30e21d220e22 --- /dev/null +++ b/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.rs @@ -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 = 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 = 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 = 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(); +} diff --git a/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.stderr b/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.stderr new file mode 100644 index 0000000000000..e8b4b06604c3d --- /dev/null +++ b/tests/ui/borrowck/buffer-reuse-pattern-issue-147694.stderr @@ -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 = 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 = 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 = 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`. diff --git a/tests/ui/issues/issue-52126-assign-op-invariance.stderr b/tests/ui/issues/issue-52126-assign-op-invariance.stderr index af9553e5cf382..dd38a1061baaa 100644 --- a/tests/ui/issues/issue-52126-assign-op-invariance.stderr +++ b/tests/ui/issues/issue-52126-assign-op-invariance.stderr @@ -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 diff --git a/tests/ui/span/borrowck-let-suggestion-suffixes.rs b/tests/ui/span/borrowck-let-suggestion-suffixes.rs index ad556f281df12..c8acbfadacd37 100644 --- a/tests/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/tests/ui/span/borrowck-let-suggestion-suffixes.rs @@ -3,6 +3,7 @@ fn id(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 diff --git a/tests/ui/span/borrowck-let-suggestion-suffixes.stderr b/tests/ui/span/borrowck-let-suggestion-suffixes.stderr index 78cadc8c694ec..cdffbd2145fc4 100644 --- a/tests/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/tests/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -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 diff --git a/tests/ui/span/regions-escape-loop-via-vec.stderr b/tests/ui/span/regions-escape-loop-via-vec.stderr index 18c6cd4809303..46d70e7482f34 100644 --- a/tests/ui/span/regions-escape-loop-via-vec.stderr +++ b/tests/ui/span/regions-escape-loop-via-vec.stderr @@ -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