Skip to content

Commit 1224847

Browse files
committed
Suggest a borrow when using dbg
1 parent e612d07 commit 1224847

File tree

4 files changed

+250
-9
lines changed

4 files changed

+250
-9
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+89-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![allow(rustc::untranslatable_diagnostic)]
55

66
use either::Either;
7+
use hir::Path;
78
use rustc_data_structures::captures::Captures;
89
use rustc_data_structures::fx::FxIndexSet;
910
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -27,11 +28,13 @@ use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
2728
use rustc_span::def_id::LocalDefId;
2829
use rustc_span::hygiene::DesugaringKind;
2930
use rustc_span::symbol::{kw, sym, Ident};
31+
use rustc_span::FileName;
3032
use rustc_span::{BytePos, Span, Symbol};
3133
use rustc_trait_selection::infer::InferCtxtExt;
3234
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
3335
use rustc_trait_selection::traits::ObligationCtxt;
3436
use std::iter;
37+
use std::path::PathBuf;
3538

3639
use crate::borrow_set::TwoPhaseActivation;
3740
use crate::borrowck_errors;
@@ -463,19 +466,96 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
463466
self.suggest_cloning(err, ty, expr, move_span);
464467
}
465468
}
469+
470+
self.suggest_ref_for_dbg_args(expr, span, move_span, err);
471+
466472
if let Some(pat) = finder.pat {
467-
*in_pattern = true;
468-
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
469-
if let Some(pat) = finder.parent_pat {
470-
sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
471-
}
472-
err.multipart_suggestion_verbose(
473-
"borrow this binding in the pattern to avoid moving the value",
474-
sugg,
475-
Applicability::MachineApplicable,
473+
// FIXME: any better way to check this?
474+
let from_std = self.infcx.tcx.sess.opts.real_rust_source_base_dir.clone().map_or(
475+
false,
476+
|root| {
477+
let file_path =
478+
match self.infcx.tcx.sess.source_map().span_to_filename(move_span) {
479+
FileName::Real(name) => {
480+
name.clone().into_local_path().unwrap_or_default()
481+
}
482+
other => PathBuf::from(other.prefer_local().to_string()),
483+
};
484+
file_path.starts_with(&root.join("library/std/"))
485+
},
476486
);
487+
// it's useless to suggest inserting `ref` when the span comes from std library
488+
// anyway, user can not modify std library in most cases, so let's keep it quite?
489+
if !from_std {
490+
*in_pattern = true;
491+
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
492+
if let Some(pat) = finder.parent_pat {
493+
sugg.insert(0, (pat.span.shrink_to_lo(), "ref ".to_string()));
494+
}
495+
err.multipart_suggestion_verbose(
496+
"borrow this binding in the pattern to avoid moving the value",
497+
sugg,
498+
Applicability::MachineApplicable,
499+
);
500+
}
501+
}
502+
}
503+
}
504+
505+
// for dbg!(x) which may take onwership, suggest dbg!(&x) instead
506+
// but here we actually does not checking the macro name is `dbg!`
507+
// so that we may extend the scope a bit larger to cover more cases
508+
fn suggest_ref_for_dbg_args(
509+
&self,
510+
body: &hir::Expr<'_>,
511+
span: Option<Span>,
512+
move_span: Span,
513+
err: &mut Diag<'tcx>,
514+
) {
515+
// only suggest for macro
516+
if move_span.source_callsite() == move_span {
517+
return;
518+
}
519+
let sm = self.infcx.tcx.sess.source_map();
520+
let arg_code = if let Some(span) = span
521+
&& let Ok(code) = sm.span_to_snippet(span)
522+
{
523+
code
524+
} else {
525+
return;
526+
};
527+
struct MatchArgFinder {
528+
expr_span: Span,
529+
match_arg_span: Option<Span>,
530+
arg_code: String,
531+
}
532+
impl Visitor<'_> for MatchArgFinder {
533+
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
534+
// dbg! is expanded into a match pattern, we need to find the right argument span
535+
if let hir::ExprKind::Match(expr, ..) = &e.kind
536+
&& let hir::ExprKind::Path(hir::QPath::Resolved(
537+
_,
538+
path @ Path { segments: [seg], .. },
539+
)) = &expr.kind
540+
&& seg.ident.name.as_str() == &self.arg_code
541+
&& self.expr_span.source_callsite().contains(expr.span)
542+
{
543+
self.match_arg_span = Some(path.span);
544+
}
545+
hir::intravisit::walk_expr(self, e);
477546
}
478547
}
548+
549+
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_code };
550+
finder.visit_expr(body);
551+
if let Some(macro_arg_span) = finder.match_arg_span {
552+
err.span_suggestion_verbose(
553+
macro_arg_span.shrink_to_lo(),
554+
"consider borrowing instead of transferring ownership",
555+
"&",
556+
Applicability::MachineApplicable,
557+
);
558+
}
479559
}
480560

481561
fn report_use_of_uninitialized(

tests/ui/borrowck/dbg-issue-120327.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
fn s() -> String {
2+
let a = String::new();
3+
dbg!(a);
4+
return a; //~ ERROR use of moved value:
5+
}
6+
7+
fn m() -> String {
8+
let a = String::new();
9+
dbg!(1, 2, a, 1, 2);
10+
return a; //~ ERROR use of moved value:
11+
}
12+
13+
fn t(a: String) -> String {
14+
let b: String = "".to_string();
15+
dbg!(a, b);
16+
return b; //~ ERROR use of moved value:
17+
}
18+
19+
fn x(a: String) -> String {
20+
let b: String = "".to_string();
21+
dbg!(a, b);
22+
return a; //~ ERROR use of moved value:
23+
}
24+
25+
macro_rules! my_dbg {
26+
() => {
27+
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
28+
};
29+
($val:expr $(,)?) => {
30+
match $val {
31+
tmp => {
32+
eprintln!("[{}:{}:{}] {} = {:#?}",
33+
file!(), line!(), column!(), stringify!($val), &tmp);
34+
tmp
35+
}
36+
}
37+
};
38+
($($val:expr),+ $(,)?) => {
39+
($(my_dbg!($val)),+,)
40+
};
41+
}
42+
43+
fn test_my_dbg() -> String {
44+
let b: String = "".to_string();
45+
my_dbg!(b, 1);
46+
return b; //~ ERROR use of moved value:
47+
}
48+
49+
fn get_expr(_s: String) {}
50+
51+
fn test() {
52+
let a: String = "".to_string();
53+
let _res = get_expr(dbg!(a));
54+
let _l = a.len(); //~ ERROR borrow of moved value
55+
}
56+
57+
fn main() {}
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
error[E0382]: use of moved value: `a`
2+
--> $DIR/dbg-issue-120327.rs:4:12
3+
|
4+
LL | let a = String::new();
5+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
6+
LL | dbg!(a);
7+
| ------- value moved here
8+
LL | return a;
9+
| ^ value used here after move
10+
|
11+
help: consider borrowing instead of transferring ownership
12+
|
13+
LL | dbg!(&a);
14+
| +
15+
16+
error[E0382]: use of moved value: `a`
17+
--> $DIR/dbg-issue-120327.rs:10:12
18+
|
19+
LL | let a = String::new();
20+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
21+
LL | dbg!(1, 2, a, 1, 2);
22+
| ------------------- value moved here
23+
LL | return a;
24+
| ^ value used here after move
25+
|
26+
help: consider borrowing instead of transferring ownership
27+
|
28+
LL | dbg!(1, 2, &a, 1, 2);
29+
| +
30+
31+
error[E0382]: use of moved value: `b`
32+
--> $DIR/dbg-issue-120327.rs:16:12
33+
|
34+
LL | let b: String = "".to_string();
35+
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
36+
LL | dbg!(a, b);
37+
| ---------- value moved here
38+
LL | return b;
39+
| ^ value used here after move
40+
|
41+
help: consider borrowing instead of transferring ownership
42+
|
43+
LL | dbg!(a, &b);
44+
| +
45+
46+
error[E0382]: use of moved value: `a`
47+
--> $DIR/dbg-issue-120327.rs:22:12
48+
|
49+
LL | fn x(a: String) -> String {
50+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
51+
LL | let b: String = "".to_string();
52+
LL | dbg!(a, b);
53+
| ---------- value moved here
54+
LL | return a;
55+
| ^ value used here after move
56+
|
57+
help: consider borrowing instead of transferring ownership
58+
|
59+
LL | dbg!(&a, b);
60+
| +
61+
62+
error[E0382]: use of moved value: `b`
63+
--> $DIR/dbg-issue-120327.rs:46:12
64+
|
65+
LL | tmp => {
66+
| --- value moved here
67+
...
68+
LL | let b: String = "".to_string();
69+
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
70+
LL | my_dbg!(b, 1);
71+
LL | return b;
72+
| ^ value used here after move
73+
|
74+
help: consider borrowing instead of transferring ownership
75+
|
76+
LL | my_dbg!(&b, 1);
77+
| +
78+
help: borrow this binding in the pattern to avoid moving the value
79+
|
80+
LL | ref tmp => {
81+
| +++
82+
83+
error[E0382]: borrow of moved value: `a`
84+
--> $DIR/dbg-issue-120327.rs:54:14
85+
|
86+
LL | let a: String = "".to_string();
87+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
88+
LL | let _res = get_expr(dbg!(a));
89+
| ------- value moved here
90+
LL | let _l = a.len();
91+
| ^ value borrowed here after move
92+
|
93+
help: consider borrowing instead of transferring ownership
94+
|
95+
LL | let _res = get_expr(dbg!(&a));
96+
| +
97+
98+
error: aborting due to 6 previous errors
99+
100+
For more information about this error, try `rustc --explain E0382`.

tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ LL | let _ = dbg!(a);
99
| ^^^^^^^ value used here after move
1010
|
1111
= note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
12+
help: consider borrowing instead of transferring ownership
13+
|
14+
LL | let _ = dbg!(&a);
15+
| +
1216

1317
error: aborting due to 1 previous error
1418

0 commit comments

Comments
 (0)