Skip to content

Commit 984ef42

Browse files
authored
Rollup merge of #99258 - estebank:suggest-let, r=wesleywiser
Provide structured suggestion for dropped temp value
2 parents 79857a7 + 3ee4e5f commit 984ef42

19 files changed

+220
-31
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+65-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_errors::{
77
};
88
use rustc_hir as hir;
99
use rustc_hir::def_id::DefId;
10-
use rustc_hir::intravisit::{walk_expr, Visitor};
10+
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
1111
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
1212
use rustc_infer::infer::TyCtxtInferExt;
1313
use rustc_infer::traits::ObligationCause;
@@ -1500,7 +1500,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15001500
| BorrowExplanation::UsedLaterInLoop(..)
15011501
| BorrowExplanation::UsedLaterWhenDropped { .. } => {
15021502
// Only give this note and suggestion if it could be relevant.
1503-
err.note("consider using a `let` binding to create a longer lived value");
1503+
let sm = self.infcx.tcx.sess.source_map();
1504+
let mut suggested = false;
1505+
let msg = "consider using a `let` binding to create a longer lived value";
1506+
1507+
/// We check that there's a single level of block nesting to ensure always correct
1508+
/// suggestions. If we don't, then we only provide a free-form message to avoid
1509+
/// misleading users in cases like `src/test/ui/nll/borrowed-temporary-error.rs`.
1510+
/// We could expand the analysis to suggest hoising all of the relevant parts of
1511+
/// the users' code to make the code compile, but that could be too much.
1512+
struct NestedStatementVisitor {
1513+
span: Span,
1514+
current: usize,
1515+
found: usize,
1516+
}
1517+
1518+
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
1519+
fn visit_block(&mut self, block: &hir::Block<'tcx>) {
1520+
self.current += 1;
1521+
walk_block(self, block);
1522+
self.current -= 1;
1523+
}
1524+
fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
1525+
if self.span == expr.span {
1526+
self.found = self.current;
1527+
}
1528+
walk_expr(self, expr);
1529+
}
1530+
}
1531+
let source_info = self.body.source_info(location);
1532+
if let Some(scope) = self.body.source_scopes.get(source_info.scope)
1533+
&& let ClearCrossCrate::Set(scope_data) = &scope.local_data
1534+
&& let Some(node) = self.infcx.tcx.hir().find(scope_data.lint_root)
1535+
&& let Some(id) = node.body_id()
1536+
&& let hir::ExprKind::Block(block, _) = self.infcx.tcx.hir().body(id).value.kind
1537+
{
1538+
for stmt in block.stmts {
1539+
let mut visitor = NestedStatementVisitor {
1540+
span: proper_span,
1541+
current: 0,
1542+
found: 0,
1543+
};
1544+
visitor.visit_stmt(stmt);
1545+
if visitor.found == 0
1546+
&& stmt.span.contains(proper_span)
1547+
&& let Some(p) = sm.span_to_margin(stmt.span)
1548+
&& let Ok(s) = sm.span_to_snippet(proper_span)
1549+
{
1550+
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
1551+
err.multipart_suggestion_verbose(
1552+
msg,
1553+
vec![
1554+
(stmt.span.shrink_to_lo(), addition),
1555+
(proper_span, "binding".to_string()),
1556+
],
1557+
Applicability::MaybeIncorrect,
1558+
);
1559+
suggested = true;
1560+
break;
1561+
}
1562+
}
1563+
}
1564+
if !suggested {
1565+
err.note(msg);
1566+
}
15041567
}
15051568
_ => {}
15061569
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
3+
use std::collections::HashMap;
4+
5+
fn main() {
6+
let tmp: Box<_>;
7+
let mut buggy_map: HashMap<usize, &usize> = HashMap::new();
8+
let binding = Box::new(1);
9+
buggy_map.insert(42, &*binding); //~ ERROR temporary value dropped while borrowed
10+
11+
// but it is ok if we use a temporary
12+
tmp = Box::new(2);
13+
buggy_map.insert(43, &*tmp);
14+
}

src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use std::collections::HashMap;
2-
3-
4-
1+
// run-rustfix
52

3+
use std::collections::HashMap;
64

75
fn main() {
86
let tmp: Box<_>;

src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0716]: temporary value dropped while borrowed
2-
--> $DIR/borrowck-borrowed-uniq-rvalue.rs:10:28
2+
--> $DIR/borrowck-borrowed-uniq-rvalue.rs:8:28
33
|
44
LL | buggy_map.insert(42, &*Box::new(1));
55
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -9,7 +9,11 @@ LL | buggy_map.insert(42, &*Box::new(1));
99
LL | buggy_map.insert(43, &*tmp);
1010
| --------------------------- borrow later used here
1111
|
12-
= note: consider using a `let` binding to create a longer lived value
12+
help: consider using a `let` binding to create a longer lived value
13+
|
14+
LL ~ let binding = Box::new(1);
15+
LL ~ buggy_map.insert(42, &*binding);
16+
|
1317

1418
error: aborting due to previous error
1519

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// run-rustfix
2+
fn id<T>(x: T) -> T { x }
3+
4+
fn main() {
5+
let x = Some(3);
6+
let binding = id(5);
7+
let y = x.as_ref().unwrap_or(&binding); //~ ERROR
8+
let _ = &y;
9+
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
// run-rustfix
12
fn id<T>(x: T) -> T { x }
23

34
fn main() {
45
let x = Some(3);
56
let y = x.as_ref().unwrap_or(&id(5)); //~ ERROR
6-
&y;
7+
let _ = &y;
78
}

src/test/ui/issues/issue-11493.stderr renamed to src/test/ui/borrowck/issue-11493.stderr

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
error[E0716]: temporary value dropped while borrowed
2-
--> $DIR/issue-11493.rs:5:35
2+
--> $DIR/issue-11493.rs:6:35
33
|
44
LL | let y = x.as_ref().unwrap_or(&id(5));
55
| ^^^^^ - temporary value is freed at the end of this statement
66
| |
77
| creates a temporary which is freed while still in use
8-
LL | &y;
9-
| -- borrow later used here
8+
LL | let _ = &y;
9+
| -- borrow later used here
10+
|
11+
help: consider using a `let` binding to create a longer lived value
12+
|
13+
LL ~ let binding = id(5);
14+
LL ~ let y = x.as_ref().unwrap_or(&binding);
1015
|
11-
= note: consider using a `let` binding to create a longer lived value
1216

1317
error: aborting due to previous error
1418

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-rustfix
2+
use std::cell::RefCell;
3+
4+
fn main() {
5+
let mut r = 0;
6+
let s = 0;
7+
let x = RefCell::new((&mut r,s));
8+
9+
let binding = x.borrow();
10+
let val: &_ = binding.0;
11+
//~^ ERROR temporary value dropped while borrowed [E0716]
12+
//~| NOTE temporary value is freed at the end of this statement
13+
//~| NOTE creates a temporary which is freed while still in use
14+
//~| HELP consider using a `let` binding to create a longer lived value
15+
println!("{}", val);
16+
//~^ borrow later used here
17+
}

src/test/ui/issues/issue-36082.rs renamed to src/test/ui/borrowck/issue-36082.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
use std::cell::RefCell;
23

34
fn main() {
@@ -9,7 +10,7 @@ fn main() {
910
//~^ ERROR temporary value dropped while borrowed [E0716]
1011
//~| NOTE temporary value is freed at the end of this statement
1112
//~| NOTE creates a temporary which is freed while still in use
12-
//~| NOTE consider using a `let` binding to create a longer lived value
13+
//~| HELP consider using a `let` binding to create a longer lived value
1314
println!("{}", val);
1415
//~^ borrow later used here
1516
}

src/test/ui/issues/issue-36082.stderr renamed to src/test/ui/borrowck/issue-36082.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0716]: temporary value dropped while borrowed
2-
--> $DIR/issue-36082.rs:8:19
2+
--> $DIR/issue-36082.rs:9:19
33
|
44
LL | let val: &_ = x.borrow().0;
55
| ^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -9,7 +9,11 @@ LL | let val: &_ = x.borrow().0;
99
LL | println!("{}", val);
1010
| --- borrow later used here
1111
|
12-
= note: consider using a `let` binding to create a longer lived value
12+
help: consider using a `let` binding to create a longer lived value
13+
|
14+
LL ~ let binding = x.borrow();
15+
LL ~ let val: &_ = binding.0;
16+
|
1317

1418
error: aborting due to previous error
1519

src/test/ui/cleanup-rvalue-scopes-cf.stderr

+35-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ LL | let x1 = arg(&AddFlags(1));
99
LL | (x1, x2, x3, x4, x5, x6, x7);
1010
| -- borrow later used here
1111
|
12-
= note: consider using a `let` binding to create a longer lived value
12+
help: consider using a `let` binding to create a longer lived value
13+
|
14+
LL ~ let binding = AddFlags(1);
15+
LL ~ let x1 = arg(&binding);
16+
|
1317

1418
error[E0716]: temporary value dropped while borrowed
1519
--> $DIR/cleanup-rvalue-scopes-cf.rs:27:14
@@ -22,7 +26,11 @@ LL | let x2 = AddFlags(1).get();
2226
LL | (x1, x2, x3, x4, x5, x6, x7);
2327
| -- borrow later used here
2428
|
25-
= note: consider using a `let` binding to create a longer lived value
29+
help: consider using a `let` binding to create a longer lived value
30+
|
31+
LL ~ let binding = AddFlags(1);
32+
LL ~ let x2 = binding.get();
33+
|
2634

2735
error[E0716]: temporary value dropped while borrowed
2836
--> $DIR/cleanup-rvalue-scopes-cf.rs:28:21
@@ -35,7 +43,11 @@ LL | let x3 = &*arg(&AddFlags(1));
3543
LL | (x1, x2, x3, x4, x5, x6, x7);
3644
| -- borrow later used here
3745
|
38-
= note: consider using a `let` binding to create a longer lived value
46+
help: consider using a `let` binding to create a longer lived value
47+
|
48+
LL ~ let binding = AddFlags(1);
49+
LL ~ let x3 = &*arg(&binding);
50+
|
3951

4052
error[E0716]: temporary value dropped while borrowed
4153
--> $DIR/cleanup-rvalue-scopes-cf.rs:29:24
@@ -48,7 +60,11 @@ LL | let ref x4 = *arg(&AddFlags(1));
4860
LL | (x1, x2, x3, x4, x5, x6, x7);
4961
| -- borrow later used here
5062
|
51-
= note: consider using a `let` binding to create a longer lived value
63+
help: consider using a `let` binding to create a longer lived value
64+
|
65+
LL ~ let binding = AddFlags(1);
66+
LL ~ let ref x4 = *arg(&binding);
67+
|
5268

5369
error[E0716]: temporary value dropped while borrowed
5470
--> $DIR/cleanup-rvalue-scopes-cf.rs:30:24
@@ -61,7 +77,11 @@ LL | let &ref x5 = arg(&AddFlags(1));
6177
LL | (x1, x2, x3, x4, x5, x6, x7);
6278
| -- borrow later used here
6379
|
64-
= note: consider using a `let` binding to create a longer lived value
80+
help: consider using a `let` binding to create a longer lived value
81+
|
82+
LL ~ let binding = AddFlags(1);
83+
LL ~ let &ref x5 = arg(&binding);
84+
|
6585

6686
error[E0716]: temporary value dropped while borrowed
6787
--> $DIR/cleanup-rvalue-scopes-cf.rs:31:14
@@ -74,7 +94,11 @@ LL | let x6 = AddFlags(1).get();
7494
LL | (x1, x2, x3, x4, x5, x6, x7);
7595
| -- borrow later used here
7696
|
77-
= note: consider using a `let` binding to create a longer lived value
97+
help: consider using a `let` binding to create a longer lived value
98+
|
99+
LL ~ let binding = AddFlags(1);
100+
LL ~ let x6 = binding.get();
101+
|
78102

79103
error[E0716]: temporary value dropped while borrowed
80104
--> $DIR/cleanup-rvalue-scopes-cf.rs:32:44
@@ -87,7 +111,11 @@ LL |
87111
LL | (x1, x2, x3, x4, x5, x6, x7);
88112
| -- borrow later used here
89113
|
90-
= note: consider using a `let` binding to create a longer lived value
114+
help: consider using a `let` binding to create a longer lived value
115+
|
116+
LL ~ let binding = AddFlags(1);
117+
LL ~ let StackBox { f: x7 } = StackBox { f: binding.get() };
118+
|
91119

92120
error: aborting due to 7 previous errors
93121

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fn f() {
2020
//~^ ERROR temporary value dropped while borrowed
2121
//~| NOTE creates a temporary which is freed while still in use
2222
//~| NOTE temporary value is freed at the end of this statement
23-
//~| NOTE consider using a `let` binding to create a longer lived value
23+
//~| HELP consider using a `let` binding to create a longer lived value
2424

2525
{
2626

@@ -41,7 +41,7 @@ fn f() {
4141
//~^ ERROR temporary value dropped while borrowed
4242
//~| NOTE creates a temporary which is freed while still in use
4343
//~| NOTE temporary value is freed at the end of this statement
44-
//~| NOTE consider using a `let` binding to create a longer lived value
44+
//~| HELP consider using a `let` binding to create a longer lived value
4545

4646
v1.push(&old[0]);
4747

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

+10-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ LL | v3.push(&id('x')); // statement 6
2121
LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref();
2222
| -- borrow later used here
2323
|
24-
= note: consider using a `let` binding to create a longer lived value
24+
help: consider using a `let` binding to create a longer lived value
25+
|
26+
LL ~ let binding = id('x');
27+
LL ~ v3.push(&binding); // statement 6
28+
|
2529

2630
error[E0716]: temporary value dropped while borrowed
2731
--> $DIR/borrowck-let-suggestion-suffixes.rs:29:18
@@ -47,7 +51,11 @@ LL | v5.push(&id('z'));
4751
LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref();
4852
| -- borrow later used here
4953
|
50-
= note: consider using a `let` binding to create a longer lived value
54+
help: consider using a `let` binding to create a longer lived value
55+
|
56+
LL ~ let binding = id('z');
57+
LL ~ v5.push(&binding);
58+
|
5159

5260
error: aborting due to 4 previous errors
5361

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// run-rustfix
2+
fn main() {
3+
let msg;
4+
let binding = Some("Hello".to_string());
5+
match binding {
6+
//~^ ERROR temporary value dropped while borrowed
7+
Some(ref m) => {
8+
msg = m;
9+
},
10+
None => { panic!() }
11+
}
12+
println!("{}", *msg);
13+
}

src/test/ui/span/borrowck-ref-into-rvalue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// run-rustfix
12
fn main() {
23
let msg;
34
match Some("Hello".to_string()) {

src/test/ui/span/borrowck-ref-into-rvalue.stderr

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0716]: temporary value dropped while borrowed
2-
--> $DIR/borrowck-ref-into-rvalue.rs:3:11
2+
--> $DIR/borrowck-ref-into-rvalue.rs:4:11
33
|
44
LL | match Some("Hello".to_string()) {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
@@ -9,7 +9,11 @@ LL | }
99
LL | println!("{}", *msg);
1010
| ---- borrow later used here
1111
|
12-
= note: consider using a `let` binding to create a longer lived value
12+
help: consider using a `let` binding to create a longer lived value
13+
|
14+
LL ~ let binding = Some("Hello".to_string());
15+
LL ~ match binding {
16+
|
1317

1418
error: aborting due to previous error
1519

0 commit comments

Comments
 (0)