From 20b5aaf11103d65752adafe549be1acecfa9acdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Jul 2022 17:12:01 -0700 Subject: [PATCH 1/4] Provide structured suggestion for dropped temp value --- .../src/diagnostics/conflict_errors.rs | 33 ++++++++++++++- .../borrowck-borrowed-uniq-rvalue.fixed | 14 +++++++ .../borrowck/borrowck-borrowed-uniq-rvalue.rs | 6 +-- .../borrowck-borrowed-uniq-rvalue.stderr | 8 +++- src/test/ui/cleanup-rvalue-scopes-cf.stderr | 42 +++++++++++++++---- src/test/ui/issues/issue-11493.fixed | 9 ++++ src/test/ui/issues/issue-11493.rs | 3 +- src/test/ui/issues/issue-11493.stderr | 12 ++++-- src/test/ui/issues/issue-36082.fixed | 17 ++++++++ src/test/ui/issues/issue-36082.rs | 3 +- src/test/ui/issues/issue-36082.stderr | 8 +++- .../ui/nll/borrowed-temporary-error.stderr | 8 +++- .../span/borrowck-let-suggestion-suffixes.rs | 7 ++-- .../borrowck-let-suggestion-suffixes.stderr | 24 +++++++++-- .../ui/span/borrowck-ref-into-rvalue.fixed | 13 ++++++ src/test/ui/span/borrowck-ref-into-rvalue.rs | 1 + .../ui/span/borrowck-ref-into-rvalue.stderr | 8 +++- src/test/ui/span/issue-15480.fixed | 14 +++++++ src/test/ui/span/issue-15480.rs | 1 + src/test/ui/span/issue-15480.stderr | 9 +++- 20 files changed, 205 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed create mode 100644 src/test/ui/issues/issue-11493.fixed create mode 100644 src/test/ui/issues/issue-36082.fixed create mode 100644 src/test/ui/span/borrowck-ref-into-rvalue.fixed create mode 100644 src/test/ui/span/issue-15480.fixed diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0ceb63477c8..6923fc1c1f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1500,7 +1500,38 @@ fn report_temporary_value_does_not_live_long_enough( | BorrowExplanation::UsedLaterInLoop(..) | BorrowExplanation::UsedLaterWhenDropped { .. } => { // Only give this note and suggestion if it could be relevant. - err.note("consider using a `let` binding to create a longer lived value"); + let sm = self.infcx.tcx.sess.source_map(); + let mut suggested = false; + let msg = "consider using a `let` binding to create a longer lived value"; + if let Some(scope) = + self.body.source_scopes.get(self.body.source_info(location).scope) + && let ClearCrossCrate::Set(scope_data) = &scope.local_data + && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root) + && let Some(id) = node.body_id() + && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind + { + for stmt in block.stmts { + if stmt.span.contains(proper_span) + && let Some(p) = sm.span_to_margin(stmt.span) + && let Ok(s) = sm.span_to_snippet(proper_span) + { + let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + err.multipart_suggestion_verbose( + msg, + vec![ + (stmt.span.shrink_to_lo(), addition), + (proper_span, "binding".to_string()), + ], + Applicability::MaybeIncorrect, + ); + suggested = true; + break; + } + } + } + if !suggested { + err.note(msg); + } } _ => {} } diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed new file mode 100644 index 00000000000..8bf6a2f6db3 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +use std::collections::HashMap; + +fn main() { + let tmp: Box<_>; + let mut buggy_map: HashMap = HashMap::new(); + let binding = Box::new(1); + buggy_map.insert(42, &*binding); //~ ERROR temporary value dropped while borrowed + + // but it is ok if we use a temporary + tmp = Box::new(2); + buggy_map.insert(43, &*tmp); +} diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs index 1d05845fc6b..85481336a30 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -1,9 +1,7 @@ +// run-rustfix + use std::collections::HashMap; - - - - fn main() { let tmp: Box<_>; let mut buggy_map: HashMap = HashMap::new(); diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr index 01379ed8512..dea8ac90bec 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:28 + --> $DIR/borrowck-borrowed-uniq-rvalue.rs:8:28 | LL | buggy_map.insert(42, &*Box::new(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -9,7 +9,11 @@ LL | buggy_map.insert(42, &*Box::new(1)); LL | buggy_map.insert(43, &*tmp); | --------------------------- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Box::new(1); +LL ~ buggy_map.insert(42, &*binding); + | error: aborting due to previous error diff --git a/src/test/ui/cleanup-rvalue-scopes-cf.stderr b/src/test/ui/cleanup-rvalue-scopes-cf.stderr index 04e599755fb..40f14c38984 100644 --- a/src/test/ui/cleanup-rvalue-scopes-cf.stderr +++ b/src/test/ui/cleanup-rvalue-scopes-cf.stderr @@ -9,7 +9,11 @@ LL | let x1 = arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x1 = arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14 @@ -22,7 +26,11 @@ LL | let x2 = AddFlags(1).get(); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x2 = binding.get(); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21 @@ -35,7 +43,11 @@ LL | let x3 = &*arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x3 = &*arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24 @@ -48,7 +60,11 @@ LL | let ref x4 = *arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let ref x4 = *arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24 @@ -61,7 +77,11 @@ LL | let &ref x5 = arg(&AddFlags(1)); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let &ref x5 = arg(&binding); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14 @@ -74,7 +94,11 @@ LL | let x6 = AddFlags(1).get(); LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let x6 = binding.get(); + | error[E0716]: temporary value dropped while borrowed --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44 @@ -87,7 +111,11 @@ LL | LL | (x1, x2, x3, x4, x5, x6, x7); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = AddFlags(1); +LL ~ let StackBox { f: x7 } = StackBox { f: binding.get() }; + | error: aborting due to 7 previous errors diff --git a/src/test/ui/issues/issue-11493.fixed b/src/test/ui/issues/issue-11493.fixed new file mode 100644 index 00000000000..139bd9a0739 --- /dev/null +++ b/src/test/ui/issues/issue-11493.fixed @@ -0,0 +1,9 @@ +// run-rustfix +fn id(x: T) -> T { x } + +fn main() { + let x = Some(3); + let binding = id(5); + let y = x.as_ref().unwrap_or(&binding); //~ ERROR + let _ = &y; +} diff --git a/src/test/ui/issues/issue-11493.rs b/src/test/ui/issues/issue-11493.rs index b28c173b19b..cb77f89fb2b 100644 --- a/src/test/ui/issues/issue-11493.rs +++ b/src/test/ui/issues/issue-11493.rs @@ -1,7 +1,8 @@ +// run-rustfix fn id(x: T) -> T { x } fn main() { let x = Some(3); let y = x.as_ref().unwrap_or(&id(5)); //~ ERROR - &y; + let _ = &y; } diff --git a/src/test/ui/issues/issue-11493.stderr b/src/test/ui/issues/issue-11493.stderr index f954d64ac5b..a5d1f2816f1 100644 --- a/src/test/ui/issues/issue-11493.stderr +++ b/src/test/ui/issues/issue-11493.stderr @@ -1,14 +1,18 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-11493.rs:5:35 + --> $DIR/issue-11493.rs:6:35 | LL | let y = x.as_ref().unwrap_or(&id(5)); | ^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary which is freed while still in use -LL | &y; - | -- borrow later used here +LL | let _ = &y; + | -- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id(5); +LL ~ let y = x.as_ref().unwrap_or(&binding); | - = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36082.fixed b/src/test/ui/issues/issue-36082.fixed new file mode 100644 index 00000000000..8640ca7a509 --- /dev/null +++ b/src/test/ui/issues/issue-36082.fixed @@ -0,0 +1,17 @@ +// run-rustfix +use std::cell::RefCell; + +fn main() { + let mut r = 0; + let s = 0; + let x = RefCell::new((&mut r,s)); + + let binding = x.borrow(); + let val: &_ = binding.0; + //~^ ERROR temporary value dropped while borrowed [E0716] + //~| NOTE temporary value is freed at the end of this statement + //~| NOTE creates a temporary which is freed while still in use + //~| HELP consider using a `let` binding to create a longer lived value + println!("{}", val); + //~^ borrow later used here +} diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/issues/issue-36082.rs index a2ff477eb81..877d372fb84 100644 --- a/src/test/ui/issues/issue-36082.rs +++ b/src/test/ui/issues/issue-36082.rs @@ -1,3 +1,4 @@ +// run-rustfix use std::cell::RefCell; fn main() { @@ -9,7 +10,7 @@ fn main() { //~^ ERROR temporary value dropped while borrowed [E0716] //~| NOTE temporary value is freed at the end of this statement //~| NOTE creates a temporary which is freed while still in use - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value println!("{}", val); //~^ borrow later used here } diff --git a/src/test/ui/issues/issue-36082.stderr b/src/test/ui/issues/issue-36082.stderr index 26bf4cb1be8..4bd586db1cd 100644 --- a/src/test/ui/issues/issue-36082.stderr +++ b/src/test/ui/issues/issue-36082.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-36082.rs:8:19 + --> $DIR/issue-36082.rs:9:19 | LL | let val: &_ = x.borrow().0; | ^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -9,7 +9,11 @@ LL | let val: &_ = x.borrow().0; LL | println!("{}", val); | --- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = x.borrow(); +LL ~ let val: &_ = binding.0; + | error: aborting due to previous error diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr index 2c6bd92641f..59e6dd61b0f 100644 --- a/src/test/ui/nll/borrowed-temporary-error.stderr +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -9,7 +9,13 @@ LL | }); LL | println!("{:?}", x); | - borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = (v,); +LL ~ let x = gimme({ +LL | let v = 22; +LL ~ &binding + | error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 4744f3710ce..70e136e7e61 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -20,9 +20,9 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value - { + { //~ HELP consider using a `let` binding to create a longer lived value let mut v4 = Vec::new(); // (sub) statement 0 @@ -30,7 +30,6 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement - //~| NOTE consider using a `let` binding to create a longer lived value v4.use_ref(); //~^ NOTE borrow later used here } // (statement 7) @@ -41,7 +40,7 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement - //~| NOTE consider using a `let` binding to create a longer lived value + //~| HELP consider using a `let` binding to create a longer lived value v1.push(&old[0]); diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 7c5caba6eae..ab68d111597 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -21,7 +21,11 @@ LL | v3.push(&id('x')); // statement 6 LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id('x'); +LL ~ v3.push(&binding); // statement 6 + | error[E0716]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:29:18 @@ -34,10 +38,18 @@ LL | v4.push(&id('y')); LL | v4.use_ref(); | ------------ borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id('y'); +LL ~ { +LL | +LL | let mut v4 = Vec::new(); // (sub) statement 0 +LL | +LL ~ v4.push(&binding); + | error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:39:14 | LL | v5.push(&id('z')); | ^^^^^^^ - temporary value is freed at the end of this statement @@ -47,7 +59,11 @@ LL | v5.push(&id('z')); LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id('z'); +LL ~ v5.push(&binding); + | error: aborting due to 4 previous errors diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.fixed b/src/test/ui/span/borrowck-ref-into-rvalue.fixed new file mode 100644 index 00000000000..51f65e5345d --- /dev/null +++ b/src/test/ui/span/borrowck-ref-into-rvalue.fixed @@ -0,0 +1,13 @@ +// run-rustfix +fn main() { + let msg; + let binding = Some("Hello".to_string()); + match binding { + //~^ ERROR temporary value dropped while borrowed + Some(ref m) => { + msg = m; + }, + None => { panic!() } + } + println!("{}", *msg); +} diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.rs b/src/test/ui/span/borrowck-ref-into-rvalue.rs index c11aa1af540..7b09fad927f 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.rs +++ b/src/test/ui/span/borrowck-ref-into-rvalue.rs @@ -1,3 +1,4 @@ +// run-rustfix fn main() { let msg; match Some("Hello".to_string()) { diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.stderr index 4f529ce9511..cb5289d24b4 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.stderr +++ b/src/test/ui/span/borrowck-ref-into-rvalue.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/borrowck-ref-into-rvalue.rs:3:11 + --> $DIR/borrowck-ref-into-rvalue.rs:4:11 | LL | match Some("Hello".to_string()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use @@ -9,7 +9,11 @@ LL | } LL | println!("{}", *msg); | ---- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = Some("Hello".to_string()); +LL ~ match binding { + | error: aborting due to previous error diff --git a/src/test/ui/span/issue-15480.fixed b/src/test/ui/span/issue-15480.fixed new file mode 100644 index 00000000000..e6d1a4dd328 --- /dev/null +++ b/src/test/ui/span/issue-15480.fixed @@ -0,0 +1,14 @@ +// run-rustfix +fn id(x: T) -> T { x } + +fn main() { + let binding = id(3); + let v = vec![ + &binding + ]; + //~^^ ERROR temporary value dropped while borrowed + + for &&x in &v { + println!("{}", x + 3); + } +} diff --git a/src/test/ui/span/issue-15480.rs b/src/test/ui/span/issue-15480.rs index b286d94178a..916ce4b1edb 100644 --- a/src/test/ui/span/issue-15480.rs +++ b/src/test/ui/span/issue-15480.rs @@ -1,3 +1,4 @@ +// run-rustfix fn id(x: T) -> T { x } fn main() { diff --git a/src/test/ui/span/issue-15480.stderr b/src/test/ui/span/issue-15480.stderr index 23ee2256dd8..460ad9ac744 100644 --- a/src/test/ui/span/issue-15480.stderr +++ b/src/test/ui/span/issue-15480.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-15480.rs:5:10 + --> $DIR/issue-15480.rs:6:10 | LL | &id(3) | ^^^^^ creates a temporary which is freed while still in use @@ -9,7 +9,12 @@ LL | ]; LL | for &&x in &v { | -- borrow later used here | - = note: consider using a `let` binding to create a longer lived value +help: consider using a `let` binding to create a longer lived value + | +LL ~ let binding = id(3); +LL ~ let v = vec![ +LL ~ &binding + | error: aborting due to previous error From 635c38187bbd7adc10abf417c68b1ff06753ff5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Jul 2022 18:41:12 -0700 Subject: [PATCH 2/4] Avoid incorrect suggestion We check that there's a single level of block nesting to ensure always correct suggestions. If we don't, then we only provide a free-form message to avoid misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. We could expand the analysis to suggest hoising all of the relevant parts of the users' code to make the code compile, but that could be too much. --- .../src/diagnostics/conflict_errors.rs | 40 +++++++++++++++++-- .../ui/nll/borrowed-temporary-error.stderr | 8 +--- .../span/borrowck-let-suggestion-suffixes.rs | 3 +- .../borrowck-let-suggestion-suffixes.stderr | 12 +----- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6923fc1c1f6..c4eed784b88 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1503,15 +1503,49 @@ fn report_temporary_value_does_not_live_long_enough( let sm = self.infcx.tcx.sess.source_map(); let mut suggested = false; let msg = "consider using a `let` binding to create a longer lived value"; - if let Some(scope) = - self.body.source_scopes.get(self.body.source_info(location).scope) + + use rustc_hir::intravisit::Visitor; + + /// We check that there's a single level of block nesting to ensure always correct + /// suggestions. If we don't, then we only provide a free-form message to avoid + /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. + /// We could expand the analysis to suggest hoising all of the relevant parts of + /// the users' code to make the code compile, but that could be too much. + struct NestedStatementVisitor { + span: Span, + current: usize, + found: usize, + } + + impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { + fn visit_block(&mut self, block: &hir::Block<'tcx>) { + self.current += 1; + rustc_hir::intravisit::walk_block(self, block); + self.current -= 1; + } + fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { + if self.span == expr.span { + self.found = self.current; + } + rustc_hir::intravisit::walk_expr(self, expr); + } + } + let source_info = self.body.source_info(location); + if let Some(scope) = self.body.source_scopes.get(source_info.scope) && let ClearCrossCrate::Set(scope_data) = &scope.local_data && let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root) && let Some(id) = node.body_id() && let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind { for stmt in block.stmts { - if stmt.span.contains(proper_span) + let mut visitor = NestedStatementVisitor { + span: proper_span, + current: 0, + found: 0, + }; + visitor.visit_stmt(stmt); + if visitor.found == 0 + && stmt.span.contains(proper_span) && let Some(p) = sm.span_to_margin(stmt.span) && let Ok(s) = sm.span_to_snippet(proper_span) { diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr index 59e6dd61b0f..2c6bd92641f 100644 --- a/src/test/ui/nll/borrowed-temporary-error.stderr +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -9,13 +9,7 @@ LL | }); LL | println!("{:?}", x); | - borrow later used here | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = (v,); -LL ~ let x = gimme({ -LL | let v = 22; -LL ~ &binding - | + = note: consider using a `let` binding to create a longer lived value error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 70e136e7e61..6240f103c99 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -22,7 +22,7 @@ fn f() { //~| NOTE temporary value is freed at the end of this statement //~| HELP consider using a `let` binding to create a longer lived value - { //~ HELP consider using a `let` binding to create a longer lived value + { let mut v4 = Vec::new(); // (sub) statement 0 @@ -30,6 +30,7 @@ fn f() { //~^ ERROR temporary value dropped while borrowed //~| NOTE creates a temporary which is freed while still in use //~| NOTE temporary value is freed at the end of this statement + //~| NOTE consider using a `let` binding to create a longer lived value v4.use_ref(); //~^ NOTE borrow later used here } // (statement 7) diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index ab68d111597..a236dab3ae5 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -38,18 +38,10 @@ LL | v4.push(&id('y')); LL | v4.use_ref(); | ------------ borrow later used here | -help: consider using a `let` binding to create a longer lived value - | -LL ~ let binding = id('y'); -LL ~ { -LL | -LL | let mut v4 = Vec::new(); // (sub) statement 0 -LL | -LL ~ v4.push(&binding); - | + = 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:39:14 + --> $DIR/borrowck-let-suggestion-suffixes.rs:40:14 | LL | v5.push(&id('z')); | ^^^^^^^ - temporary value is freed at the end of this statement From 3e5809d94ff642c4ae9ed80e46d3715fdf2c50c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 14 Jul 2022 18:43:41 -0700 Subject: [PATCH 3/4] Move tests to fit in limit --- src/test/ui/{issues => borrowck}/issue-11493.fixed | 0 src/test/ui/{issues => borrowck}/issue-11493.rs | 0 src/test/ui/{issues => borrowck}/issue-11493.stderr | 0 src/test/ui/{issues => borrowck}/issue-36082.fixed | 0 src/test/ui/{issues => borrowck}/issue-36082.rs | 0 src/test/ui/{issues => borrowck}/issue-36082.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{issues => borrowck}/issue-11493.fixed (100%) rename src/test/ui/{issues => borrowck}/issue-11493.rs (100%) rename src/test/ui/{issues => borrowck}/issue-11493.stderr (100%) rename src/test/ui/{issues => borrowck}/issue-36082.fixed (100%) rename src/test/ui/{issues => borrowck}/issue-36082.rs (100%) rename src/test/ui/{issues => borrowck}/issue-36082.stderr (100%) diff --git a/src/test/ui/issues/issue-11493.fixed b/src/test/ui/borrowck/issue-11493.fixed similarity index 100% rename from src/test/ui/issues/issue-11493.fixed rename to src/test/ui/borrowck/issue-11493.fixed diff --git a/src/test/ui/issues/issue-11493.rs b/src/test/ui/borrowck/issue-11493.rs similarity index 100% rename from src/test/ui/issues/issue-11493.rs rename to src/test/ui/borrowck/issue-11493.rs diff --git a/src/test/ui/issues/issue-11493.stderr b/src/test/ui/borrowck/issue-11493.stderr similarity index 100% rename from src/test/ui/issues/issue-11493.stderr rename to src/test/ui/borrowck/issue-11493.stderr diff --git a/src/test/ui/issues/issue-36082.fixed b/src/test/ui/borrowck/issue-36082.fixed similarity index 100% rename from src/test/ui/issues/issue-36082.fixed rename to src/test/ui/borrowck/issue-36082.fixed diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/borrowck/issue-36082.rs similarity index 100% rename from src/test/ui/issues/issue-36082.rs rename to src/test/ui/borrowck/issue-36082.rs diff --git a/src/test/ui/issues/issue-36082.stderr b/src/test/ui/borrowck/issue-36082.stderr similarity index 100% rename from src/test/ui/issues/issue-36082.stderr rename to src/test/ui/borrowck/issue-36082.stderr From 3ee4e5f7040e2c7bca4dd39a6c5670c1a343eeb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 15 Jul 2022 11:07:20 -0700 Subject: [PATCH 4/4] Fix rebase --- .../rustc_borrowck/src/diagnostics/conflict_errors.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c4eed784b88..bc64cb81179 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -7,7 +7,7 @@ }; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::ObligationCause; @@ -1504,8 +1504,6 @@ fn report_temporary_value_does_not_live_long_enough( let mut suggested = false; let msg = "consider using a `let` binding to create a longer lived value"; - use rustc_hir::intravisit::Visitor; - /// We check that there's a single level of block nesting to ensure always correct /// suggestions. If we don't, then we only provide a free-form message to avoid /// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`. @@ -1520,14 +1518,14 @@ struct NestedStatementVisitor { impl<'tcx> Visitor<'tcx> for NestedStatementVisitor { fn visit_block(&mut self, block: &hir::Block<'tcx>) { self.current += 1; - rustc_hir::intravisit::walk_block(self, block); + walk_block(self, block); self.current -= 1; } fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) { if self.span == expr.span { self.found = self.current; } - rustc_hir::intravisit::walk_expr(self, expr); + walk_expr(self, expr); } } let source_info = self.body.source_info(location);