about summary refs log tree commit diff
diff options
context:
space:
mode:
authoryukang <moorekang@gmail.com>2023-08-05 19:07:42 +0800
committeryukang <moorekang@gmail.com>2023-08-23 12:35:00 +0800
commit1f107b1ef3af6f297473c98867a94a62e329dd17 (patch)
tree28cd4b23890fa3f4fdedf6164559e4505a80159e
parenta1e1dba9cc40a90409bccb8b19e359c4bdf573e5 (diff)
downloadrust-1f107b1ef3af6f297473c98867a94a62e329dd17.tar.gz
rust-1f107b1ef3af6f297473c98867a94a62e329dd17.zip
Remove the unhelpful let binding diag comes from FormatArguments
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs50
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs16
-rw-r--r--tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr33
3 files changed, 86 insertions, 13 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index fe4a45b3898..48d09f2c2b2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2130,21 +2130,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 /// 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, '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;
                         }
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
new file mode 100644
index 00000000000..4a6c2f9ed06
--- /dev/null
+++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.rs
@@ -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);
+}
diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
new file mode 100644
index 00000000000..8221505b100
--- /dev/null
+++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr
@@ -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`.