Skip to content

Commit 1f107b1

Browse files
committed
Remove the unhelpful let binding diag comes from FormatArguments
1 parent a1e1dba commit 1f107b1

File tree

3 files changed

+86
-13
lines changed

3 files changed

+86
-13
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+37-13
Original file line numberDiff line numberDiff line change
@@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21302130
/// misleading users in cases like `tests/ui/nll/borrowed-temporary-error.rs`.
21312131
/// We could expand the analysis to suggest hoising all of the relevant parts of
21322132
/// the users' code to make the code compile, but that could be too much.
2133-
struct NestedStatementVisitor {
2133+
/// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
2134+
/// which is a special case since it's generated by the compiler.
2135+
struct NestedStatementVisitor<'tcx> {
21342136
span: Span,
21352137
current: usize,
21362138
found: usize,
2139+
prop_expr: Option<&'tcx hir::Expr<'tcx>>,
21372140
}
21382141

2139-
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
2140-
fn visit_block(&mut self, block: &hir::Block<'tcx>) {
2142+
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
2143+
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
21412144
self.current += 1;
21422145
walk_block(self, block);
21432146
self.current -= 1;
21442147
}
2145-
fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
2148+
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
21462149
if self.span == expr.span.source_callsite() {
21472150
self.found = self.current;
2151+
if self.prop_expr.is_none() {
2152+
self.prop_expr = Some(expr);
2153+
}
21482154
}
21492155
walk_expr(self, expr);
21502156
}
@@ -2162,22 +2168,40 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21622168
span: proper_span,
21632169
current: 0,
21642170
found: 0,
2171+
prop_expr: None,
21652172
};
21662173
visitor.visit_stmt(stmt);
2174+
2175+
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
2176+
let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
2177+
2178+
let is_format_arguments_item =
2179+
if let Some(expr_ty) = expr_ty
2180+
&& let ty::Adt(adt, _) = expr_ty.kind() {
2181+
self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
2182+
} else {
2183+
false
2184+
};
2185+
21672186
if visitor.found == 0
21682187
&& stmt.span.contains(proper_span)
21692188
&& let Some(p) = sm.span_to_margin(stmt.span)
21702189
&& let Ok(s) = sm.span_to_snippet(proper_span)
21712190
{
2172-
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
2173-
err.multipart_suggestion_verbose(
2174-
msg,
2175-
vec![
2176-
(stmt.span.shrink_to_lo(), addition),
2177-
(proper_span, "binding".to_string()),
2178-
],
2179-
Applicability::MaybeIncorrect,
2180-
);
2191+
if !is_format_arguments_item {
2192+
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
2193+
err.multipart_suggestion_verbose(
2194+
msg,
2195+
vec![
2196+
(stmt.span.shrink_to_lo(), addition),
2197+
(proper_span, "binding".to_string()),
2198+
],
2199+
Applicability::MaybeIncorrect,
2200+
);
2201+
} else {
2202+
err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used");
2203+
err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
2204+
}
21812205
suggested = true;
21822206
break;
21832207
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![allow(dead_code)]
2+
3+
fn bar<'a>(_: std::fmt::Arguments<'a>) {}
4+
fn main() {
5+
let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
6+
//~^ ERROR temporary value dropped while borrowed
7+
8+
bar(x);
9+
10+
let foo = format_args!("{}", "hi");
11+
//~^ ERROR temporary value dropped while borrowed
12+
bar(foo);
13+
14+
let foo = format_args!("hi"); // no placeholder in arguments, so no error
15+
bar(foo);
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0716]: temporary value dropped while borrowed
2+
--> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13
3+
|
4+
LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
6+
| |
7+
| creates a temporary value which is freed while still in use
8+
...
9+
LL | bar(x);
10+
| - borrow later used here
11+
|
12+
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
13+
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
14+
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
15+
16+
error[E0716]: temporary value dropped while borrowed
17+
--> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15
18+
|
19+
LL | let foo = format_args!("{}", "hi");
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
21+
| |
22+
| creates a temporary value which is freed while still in use
23+
LL |
24+
LL | bar(foo);
25+
| --- borrow later used here
26+
|
27+
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
28+
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
29+
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
30+
31+
error: aborting due to 2 previous errors
32+
33+
For more information about this error, try `rustc --explain E0716`.

0 commit comments

Comments
 (0)