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 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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue