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.
This commit is contained in:
parent
20b5aaf111
commit
635c38187b
4 changed files with 42 additions and 21 deletions
|
@ -1503,15 +1503,49 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
let sm = self.infcx.tcx.sess.source_map();
|
let sm = self.infcx.tcx.sess.source_map();
|
||||||
let mut suggested = false;
|
let mut suggested = false;
|
||||||
let msg = "consider using a `let` binding to create a longer lived value";
|
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 ClearCrossCrate::Set(scope_data) = &scope.local_data
|
||||||
&& let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
|
&& let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
|
||||||
&& let Some(id) = node.body_id()
|
&& let Some(id) = node.body_id()
|
||||||
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
|
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
|
||||||
{
|
{
|
||||||
for stmt in block.stmts {
|
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 Some(p) = sm.span_to_margin(stmt.span)
|
||||||
&& let Ok(s) = sm.span_to_snippet(proper_span)
|
&& let Ok(s) = sm.span_to_snippet(proper_span)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,13 +9,7 @@ LL | });
|
||||||
LL | println!("{:?}", x);
|
LL | println!("{:?}", x);
|
||||||
| - borrow later used here
|
| - borrow later used here
|
||||||
|
|
|
|
||||||
help: consider using a `let` binding to create a longer lived value
|
= note: 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
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn f() {
|
||||||
//~| NOTE temporary value is freed at the end of this statement
|
//~| 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
|
||||||
|
|
||||||
{ //~ HELP consider using a `let` binding to create a longer lived value
|
{
|
||||||
|
|
||||||
let mut v4 = Vec::new(); // (sub) statement 0
|
let mut v4 = Vec::new(); // (sub) statement 0
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ fn f() {
|
||||||
//~^ ERROR temporary value dropped while borrowed
|
//~^ ERROR temporary value dropped while borrowed
|
||||||
//~| NOTE creates a temporary which is freed while still in use
|
//~| NOTE creates a temporary which is freed while still in use
|
||||||
//~| NOTE temporary value is freed at the end of this statement
|
//~| 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();
|
v4.use_ref();
|
||||||
//~^ NOTE borrow later used here
|
//~^ NOTE borrow later used here
|
||||||
} // (statement 7)
|
} // (statement 7)
|
||||||
|
|
|
@ -38,18 +38,10 @@ LL | v4.push(&id('y'));
|
||||||
LL | v4.use_ref();
|
LL | v4.use_ref();
|
||||||
| ------------ borrow later used here
|
| ------------ borrow later used here
|
||||||
|
|
|
|
||||||
help: consider using a `let` binding to create a longer lived value
|
= note: 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
|
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'));
|
LL | v5.push(&id('z'));
|
||||||
| ^^^^^^^ - temporary value is freed at the end of this statement
|
| ^^^^^^^ - temporary value is freed at the end of this statement
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue