Remove the unhelpful let binding diag comes from FormatArguments

This commit is contained in:
yukang 2023-08-05 19:07:42 +08:00
parent a1e1dba9cc
commit 1f107b1ef3
3 changed files with 86 additions and 13 deletions

View File

@ -2130,21 +2130,27 @@ fn report_temporary_value_does_not_live_long_enough(
/// misleading users in cases like `tests/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 {
/// We found the `prop_expr` by the way to check whether the expression is a `FormatArguments`,
/// which is a special case since it's generated by the compiler.
struct NestedStatementVisitor<'tcx> {
span: Span,
current: usize,
found: usize,
prop_expr: Option<&'tcx hir::Expr<'tcx>>,
}
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor {
fn visit_block(&mut self, block: &hir::Block<'tcx>) {
impl<'tcx> Visitor<'tcx> for NestedStatementVisitor<'tcx> {
fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
self.current += 1;
walk_block(self, block);
self.current -= 1;
}
fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if self.span == expr.span.source_callsite() {
self.found = self.current;
if self.prop_expr.is_none() {
self.prop_expr = Some(expr);
}
}
walk_expr(self, expr);
}
@ -2162,22 +2168,40 @@ fn visit_expr(&mut self, expr: &hir::Expr<'tcx>) {
span: proper_span,
current: 0,
found: 0,
prop_expr: None,
};
visitor.visit_stmt(stmt);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
let is_format_arguments_item =
if let Some(expr_ty) = expr_ty
&& let ty::Adt(adt, _) = expr_ty.kind() {
self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did())
} else {
false
};
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)
{
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
err.multipart_suggestion_verbose(
msg,
vec![
(stmt.span.shrink_to_lo(), addition),
(proper_span, "binding".to_string()),
],
Applicability::MaybeIncorrect,
);
if !is_format_arguments_item {
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
err.multipart_suggestion_verbose(
msg,
vec![
(stmt.span.shrink_to_lo(), addition),
(proper_span, "binding".to_string()),
],
Applicability::MaybeIncorrect,
);
} else {
err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used");
err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
}
suggested = true;
break;
}

View File

@ -0,0 +1,16 @@
#![allow(dead_code)]
fn bar<'a>(_: std::fmt::Arguments<'a>) {}
fn main() {
let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
//~^ ERROR temporary value dropped while borrowed
bar(x);
let foo = format_args!("{}", "hi");
//~^ ERROR temporary value dropped while borrowed
bar(foo);
let foo = format_args!("hi"); // no placeholder in arguments, so no error
bar(foo);
}

View File

@ -0,0 +1,33 @@
error[E0716]: temporary value dropped while borrowed
--> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13
|
LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
...
LL | bar(x);
| - borrow later used here
|
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0716]: temporary value dropped while borrowed
--> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15
|
LL | let foo = format_args!("{}", "hi");
| ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
| |
| creates a temporary value which is freed while still in use
LL |
LL | bar(foo);
| --- borrow later used here
|
= note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
= note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0716`.