Skip to content

Commit 635c381

Browse files
committed
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.
1 parent 20b5aaf commit 635c381

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -1503,15 +1503,49 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15031503
let sm = self.infcx.tcx.sess.source_map();
15041504
let mut suggested = false;
15051505
let msg = "consider using a `let` binding to create a longer lived value";
1506-
if let Some(scope) =
1507-
self.body.source_scopes.get(self.body.source_info(location).scope)
1506+
1507+
use rustc_hir::intravisit::Visitor;
1508+
1509+
/// We check that there's a single level of block nesting to ensure always correct
1510+
/// suggestions. If we don't, then we only provide a free-form message to avoid
1511+
/// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`.
1512+
/// We could expand the analysis to suggest hoising all of the relevant parts of
1513+
/// the users' code to make the code compile, but that could be too much.
1514+
struct NestedStatementVisitor {
1515+
span: Span,
1516+
current: usize,
1517+
found: usize,
1518+
}
1519+
1520+
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
1521+
fn visit_block(&mut self, block: &hir::Block<'tcx>) {
1522+
self.current += 1;
1523+
rustc_hir::intravisit::walk_block(self, block);
1524+
self.current -= 1;
1525+
}
1526+
fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
1527+
if self.span == expr.span {
1528+
self.found = self.current;
1529+
}
1530+
rustc_hir::intravisit::walk_expr(self, expr);
1531+
}
1532+
}
1533+
let source_info = self.body.source_info(location);
1534+
if let Some(scope) = self.body.source_scopes.get(source_info.scope)
15081535
&& let ClearCrossCrate::Set(scope_data) = &scope.local_data
15091536
&& let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
15101537
&& let Some(id) = node.body_id()
15111538
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
15121539
{
15131540
for stmt in block.stmts {
1514-
if stmt.span.contains(proper_span)
1541+
let mut visitor = NestedStatementVisitor {
1542+
span: proper_span,
1543+
current: 0,
1544+
found: 0,
1545+
};
1546+
visitor.visit_stmt(stmt);
1547+
if visitor.found == 0
1548+
&& stmt.span.contains(proper_span)
15151549
&& let Some(p) = sm.span_to_margin(stmt.span)
15161550
&& let Ok(s) = sm.span_to_snippet(proper_span)
15171551
{

src/test/ui/nll/borrowed-temporary-error.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ LL | });
99
LL | println!("{:?}", x);
1010
| - borrow later used here
1111
|
12-
help: consider using a `let` binding to create a longer lived value
13-
|
14-
LL ~ let binding = (v,);
15-
LL ~ let x = gimme({
16-
LL | let v = 22;
17-
LL ~ &binding
18-
|
12+
= note: consider using a `let` binding to create a longer lived value
1913

2014
error: aborting due to previous error
2115

src/test/ui/span/borrowck-let-suggestion-suffixes.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ fn f() {
2222
//~| NOTE temporary value is freed at the end of this statement
2323
//~| HELP consider using a `let` binding to create a longer lived value
2424

25-
{ //~ HELP consider using a `let` binding to create a longer lived value
25+
{
2626

2727
let mut v4 = Vec::new(); // (sub) statement 0
2828

2929
v4.push(&id('y'));
3030
//~^ ERROR temporary value dropped while borrowed
3131
//~| NOTE creates a temporary which is freed while still in use
3232
//~| NOTE temporary value is freed at the end of this statement
33+
//~| NOTE consider using a `let` binding to create a longer lived value
3334
v4.use_ref();
3435
//~^ NOTE borrow later used here
3536
} // (statement 7)

src/test/ui/span/borrowck-let-suggestion-suffixes.stderr

+2-10
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,10 @@ LL | v4.push(&id('y'));
3838
LL | v4.use_ref();
3939
| ------------ borrow later used here
4040
|
41-
help: consider using a `let` binding to create a longer lived value
42-
|
43-
LL ~ let binding = id('y');
44-
LL ~ {
45-
LL |
46-
LL | let mut v4 = Vec::new(); // (sub) statement 0
47-
LL |
48-
LL ~ v4.push(&binding);
49-
|
41+
= note: consider using a `let` binding to create a longer lived value
5042

5143
error[E0716]: temporary value dropped while borrowed
52-
--> $DIR/borrowck-let-suggestion-suffixes.rs:39:14
44+
--> $DIR/borrowck-let-suggestion-suffixes.rs:40:14
5345
|
5446
LL | v5.push(&id('z'));
5547
| ^^^^^^^ - temporary value is freed at the end of this statement

0 commit comments

Comments
 (0)