Skip to content

Commit 6ff3713

Browse files
committed
Suggest adding semicolon in user code rather than macro impl details
1 parent 6c8138d commit 6ff3713

File tree

5 files changed

+166
-3
lines changed

5 files changed

+166
-3
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,18 @@ impl<'tcx> BorrowExplanation<'tcx> {
342342
}
343343
}
344344
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
345+
let sp = info
346+
.span
347+
.find_ancestor_in_same_ctxt(local_decl.source_info.span)
348+
.unwrap_or(info.span);
345349
if info.tail_result_is_ignored {
346350
// #85581: If the first mutable borrow's scope contains
347351
// the second borrow, this suggestion isn't helpful.
348352
if !multiple_borrow_span.is_some_and(|(old, new)| {
349353
old.to(info.span.shrink_to_hi()).contains(new)
350354
}) {
351355
err.span_suggestion_verbose(
352-
info.span.shrink_to_hi(),
356+
sp.shrink_to_hi(),
353357
"consider adding semicolon after the expression so its \
354358
temporaries are dropped sooner, before the local variables \
355359
declared by the block are dropped",
@@ -368,8 +372,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
368372
local variable `x` and then make `x` be the expression at the \
369373
end of the block",
370374
vec![
371-
(info.span.shrink_to_lo(), "let x = ".to_string()),
372-
(info.span.shrink_to_hi(), "; x".to_string()),
375+
(sp.shrink_to_lo(), "let x = ".to_string()),
376+
(sp.shrink_to_hi(), "; x".to_string()),
373377
],
374378
Applicability::MaybeIncorrect,
375379
);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Make sure the generated suggestion suggest editing the user
2+
// code instead of the std macro implementation
3+
4+
//@ run-rustfix
5+
6+
#![allow(dead_code)]
7+
8+
use std::fmt::{self, Display};
9+
10+
struct Mutex;
11+
12+
impl Mutex {
13+
fn lock(&self) -> MutexGuard<'_> {
14+
MutexGuard(self)
15+
}
16+
}
17+
18+
struct MutexGuard<'a>(&'a Mutex);
19+
20+
impl<'a> Drop for MutexGuard<'a> {
21+
fn drop(&mut self) {}
22+
}
23+
24+
struct Out;
25+
26+
impl Out {
27+
fn write_fmt(&self, _args: fmt::Arguments) {}
28+
}
29+
30+
impl<'a> Display for MutexGuard<'a> {
31+
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
32+
Ok(())
33+
}
34+
}
35+
36+
fn main() {
37+
let _write = {
38+
let mutex = Mutex;
39+
write!(Out, "{}", mutex.lock());
40+
//~^ ERROR `mutex` does not live long enough
41+
//~| SUGGESTION ;
42+
};
43+
44+
let _write = {
45+
use std::io::Write as _;
46+
47+
let mutex = Mutex;
48+
let x = write!(std::io::stdout(), "{}", mutex.lock()); x
49+
//~^ ERROR `mutex` does not live long enough
50+
//~| SUGGESTION let x
51+
};
52+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Make sure the generated suggestion suggest editing the user
2+
// code instead of the std macro implementation
3+
4+
//@ run-rustfix
5+
6+
#![allow(dead_code)]
7+
8+
use std::fmt::{self, Display};
9+
10+
struct Mutex;
11+
12+
impl Mutex {
13+
fn lock(&self) -> MutexGuard<'_> {
14+
MutexGuard(self)
15+
}
16+
}
17+
18+
struct MutexGuard<'a>(&'a Mutex);
19+
20+
impl<'a> Drop for MutexGuard<'a> {
21+
fn drop(&mut self) {}
22+
}
23+
24+
struct Out;
25+
26+
impl Out {
27+
fn write_fmt(&self, _args: fmt::Arguments) {}
28+
}
29+
30+
impl<'a> Display for MutexGuard<'a> {
31+
fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
32+
Ok(())
33+
}
34+
}
35+
36+
fn main() {
37+
let _write = {
38+
let mutex = Mutex;
39+
write!(Out, "{}", mutex.lock())
40+
//~^ ERROR `mutex` does not live long enough
41+
//~| SUGGESTION ;
42+
};
43+
44+
let _write = {
45+
use std::io::Write as _;
46+
47+
let mutex = Mutex;
48+
write!(std::io::stdout(), "{}", mutex.lock())
49+
//~^ ERROR `mutex` does not live long enough
50+
//~| SUGGESTION let x
51+
};
52+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0597]: `mutex` does not live long enough
2+
--> $DIR/span-semicolon-issue-139049.rs:39:27
3+
|
4+
LL | let mutex = Mutex;
5+
| ----- binding `mutex` declared here
6+
LL | write!(Out, "{}", mutex.lock())
7+
| ^^^^^-------
8+
| |
9+
| borrowed value does not live long enough
10+
| a temporary with access to the borrow is created here ...
11+
...
12+
LL | };
13+
| -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
14+
| |
15+
| `mutex` dropped here while still borrowed
16+
|
17+
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
18+
|
19+
LL | write!(Out, "{}", mutex.lock());
20+
| +
21+
22+
error[E0597]: `mutex` does not live long enough
23+
--> $DIR/span-semicolon-issue-139049.rs:48:41
24+
|
25+
LL | let mutex = Mutex;
26+
| ----- binding `mutex` declared here
27+
LL | write!(std::io::stdout(), "{}", mutex.lock())
28+
| ^^^^^-------
29+
| |
30+
| borrowed value does not live long enough
31+
| a temporary with access to the borrow is created here ...
32+
...
33+
LL | };
34+
| -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
35+
| |
36+
| `mutex` dropped here while still borrowed
37+
|
38+
= note: the temporary is part of an expression at the end of a block;
39+
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
40+
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
41+
|
42+
LL | let x = write!(std::io::stdout(), "{}", mutex.lock()); x
43+
| +++++++ +++
44+
45+
error: aborting due to 2 previous errors
46+
47+
For more information about this error, try `rustc --explain E0597`.

tests/ui/macros/format-args-temporaries-in-write.stderr

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ LL | };
1414
| |
1515
| `mutex` dropped here while still borrowed
1616
|
17+
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
18+
|
19+
LL | write!(Out, "{}", mutex.lock()); /* no semicolon */
20+
| +
1721

1822
error[E0597]: `mutex` does not live long enough
1923
--> $DIR/format-args-temporaries-in-write.rs:47:29
@@ -31,6 +35,10 @@ LL | };
3135
| |
3236
| `mutex` dropped here while still borrowed
3337
|
38+
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
39+
|
40+
LL | writeln!(Out, "{}", mutex.lock()); /* no semicolon */
41+
| +
3442

3543
error: aborting due to 2 previous errors
3644

0 commit comments

Comments
 (0)