about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <t.gross35@gmail.com>2024-07-16 02:02:23 -0500
committerGitHub <noreply@github.com>2024-07-16 02:02:23 -0500
commit12fd2f94b389d9510db0f8a948a98f402aeb0c0b (patch)
tree4e7a28f24ba823f47d6b5e85ac5f17ce7f97fac2
parent5c8488605624d67b272953bc21d41db60dbd5654 (diff)
parent317952677ad6a80b3751a075f42ffd2a8d142a84 (diff)
downloadrust-12fd2f94b389d9510db0f8a948a98f402aeb0c0b.tar.gz
rust-12fd2f94b389d9510db0f8a948a98f402aeb0c0b.zip
Rollup merge of #120990 - chenyukang:yukang-fix-120327-dbg, r=oli-obk
Suggest a borrow when using dbg

Fixes #120327
r? ````@estebank````
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs65
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.rs68
-rw-r--r--tests/ui/borrowck/dbg-issue-120327.stderr117
-rw-r--r--tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr4
4 files changed, 252 insertions, 2 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 1cb74849017..c7f6840e401 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -4,7 +4,7 @@
 #![allow(rustc::untranslatable_diagnostic)]
 
 use either::Either;
-use hir::ClosureKind;
+use hir::{ClosureKind, Path};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::mir::VarDebugInfoContents;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
     FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -546,7 +547,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 }
             }
-            if let Some(pat) = finder.pat {
+
+            self.suggest_ref_for_dbg_args(expr, place, move_span, err);
+
+            // it's useless to suggest inserting `ref` when the span don't comes from local code
+            if let Some(pat) = finder.pat
+                && !move_span.is_dummy()
+                && !self.infcx.tcx.sess.source_map().is_imported(move_span)
+            {
                 *in_pattern = true;
                 let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
                 if let Some(pat) = finder.parent_pat {
@@ -561,6 +569,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
         }
     }
 
+    // for dbg!(x) which may take ownership, suggest dbg!(&x) instead
+    // but here we actually do not check whether the macro name is `dbg!`
+    // so that we may extend the scope a bit larger to cover more cases
+    fn suggest_ref_for_dbg_args(
+        &self,
+        body: &hir::Expr<'_>,
+        place: &Place<'tcx>,
+        move_span: Span,
+        err: &mut Diag<'infcx>,
+    ) {
+        let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
+            VarDebugInfoContents::Place(ref p) => p == place,
+            _ => false,
+        });
+        let arg_name = if let Some(var_info) = var_info {
+            var_info.name
+        } else {
+            return;
+        };
+        struct MatchArgFinder {
+            expr_span: Span,
+            match_arg_span: Option<Span>,
+            arg_name: Symbol,
+        }
+        impl Visitor<'_> for MatchArgFinder {
+            fn visit_expr(&mut self, e: &hir::Expr<'_>) {
+                // dbg! is expanded into a match pattern, we need to find the right argument span
+                if let hir::ExprKind::Match(expr, ..) = &e.kind
+                    && let hir::ExprKind::Path(hir::QPath::Resolved(
+                        _,
+                        path @ Path { segments: [seg], .. },
+                    )) = &expr.kind
+                    && seg.ident.name == self.arg_name
+                    && self.expr_span.source_callsite().contains(expr.span)
+                {
+                    self.match_arg_span = Some(path.span);
+                }
+                hir::intravisit::walk_expr(self, e);
+            }
+        }
+
+        let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
+        finder.visit_expr(body);
+        if let Some(macro_arg_span) = finder.match_arg_span {
+            err.span_suggestion_verbose(
+                macro_arg_span.shrink_to_lo(),
+                "consider borrowing instead of transferring ownership",
+                "&",
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn report_use_of_uninitialized(
         &self,
         mpi: MovePathIndex,
diff --git a/tests/ui/borrowck/dbg-issue-120327.rs b/tests/ui/borrowck/dbg-issue-120327.rs
new file mode 100644
index 00000000000..2de43f63487
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.rs
@@ -0,0 +1,68 @@
+fn s() -> String {
+    let a = String::new();
+    dbg!(a);
+    return a; //~ ERROR use of moved value:
+}
+
+fn m() -> String {
+    let a = String::new();
+    dbg!(1, 2, a, 1, 2);
+    return a; //~ ERROR use of moved value:
+}
+
+fn t(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return b; //~ ERROR use of moved value:
+}
+
+fn x(a: String) -> String {
+    let b: String = "".to_string();
+    dbg!(a, b);
+    return a; //~ ERROR use of moved value:
+}
+
+macro_rules! my_dbg {
+    () => {
+        eprintln!("[{}:{}:{}]", file!(), line!(), column!())
+    };
+    ($val:expr $(,)?) => {
+        match $val {
+            tmp => {
+                eprintln!("[{}:{}:{}] {} = {:#?}",
+                    file!(), line!(), column!(), stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($(my_dbg!($val)),+,)
+    };
+}
+
+fn test_my_dbg() -> String {
+    let b: String = "".to_string();
+    my_dbg!(b, 1);
+    return b; //~ ERROR use of moved value:
+}
+
+fn test_not_macro() -> String {
+    let a = String::new();
+    let _b = match a {
+        tmp => {
+            eprintln!("dbg: {}", tmp);
+            tmp
+        }
+    };
+    return a; //~ ERROR use of moved value:
+}
+
+fn get_expr(_s: String) {}
+
+fn test() {
+    let a: String = "".to_string();
+    let _res = get_expr(dbg!(a));
+    let _l = a.len(); //~ ERROR borrow of moved value
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/dbg-issue-120327.stderr b/tests/ui/borrowck/dbg-issue-120327.stderr
new file mode 100644
index 00000000000..efacc0c3f13
--- /dev/null
+++ b/tests/ui/borrowck/dbg-issue-120327.stderr
@@ -0,0 +1,117 @@
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:4:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a);
+   |     ------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a);
+   |          +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:10:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(1, 2, a, 1, 2);
+   |     ------------------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(1, 2, &a, 1, 2);
+   |                +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:16:12
+   |
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(a, &b);
+   |             +
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:22:12
+   |
+LL | fn x(a: String) -> String {
+   |      - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let b: String = "".to_string();
+LL |     dbg!(a, b);
+   |     ---------- value moved here
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     dbg!(&a, b);
+   |          +
+
+error[E0382]: use of moved value: `b`
+  --> $DIR/dbg-issue-120327.rs:46:12
+   |
+LL |             tmp => {
+   |             --- value moved here
+...
+LL |     let b: String = "".to_string();
+   |         - move occurs because `b` has type `String`, which does not implement the `Copy` trait
+LL |     my_dbg!(b, 1);
+LL |     return b;
+   |            ^ value used here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     my_dbg!(&b, 1);
+   |             +
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |             ref tmp => {
+   |             +++
+
+error[E0382]: use of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:57:12
+   |
+LL |     let a = String::new();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _b = match a {
+LL |         tmp => {
+   |         --- value moved here
+...
+LL |     return a;
+   |            ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref tmp => {
+   |         +++
+
+error[E0382]: borrow of moved value: `a`
+  --> $DIR/dbg-issue-120327.rs:65:14
+   |
+LL |     let a: String = "".to_string();
+   |         - move occurs because `a` has type `String`, which does not implement the `Copy` trait
+LL |     let _res = get_expr(dbg!(a));
+   |                         ------- value moved here
+LL |     let _l = a.len();
+   |              ^ value borrowed here after move
+   |
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _res = get_expr(dbg!(&a));
+   |                              +
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index c2b9899e20d..f515cb62c7c 100644
--- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
+++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
@@ -9,6 +9,10 @@ LL |     let _ = dbg!(a);
    |             ^^^^^^^ value used here after move
    |
    = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing instead of transferring ownership
+   |
+LL |     let _ = dbg!(&a);
+   |                  +
 
 error: aborting due to 1 previous error