Skip to content

Commit 85e312f

Browse files
committed
Suggest a borrow when using dbg
1 parent 9ffe52e commit 85e312f

File tree

4 files changed

+252
-2
lines changed

4 files changed

+252
-2
lines changed

Diff for: compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

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

66
use either::Either;
7-
use hir::ClosureKind;
7+
use hir::{ClosureKind, Path};
88
use rustc_data_structures::captures::Captures;
99
use rustc_data_structures::fx::FxIndexSet;
1010
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
@@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
1616
use rustc_middle::bug;
1717
use rustc_middle::hir::nested_filter::OnlyBodies;
1818
use rustc_middle::mir::tcx::PlaceTy;
19+
use rustc_middle::mir::VarDebugInfoContents;
1920
use rustc_middle::mir::{
2021
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
2122
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
@@ -494,7 +495,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
494495
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
495496
}
496497
}
497-
if let Some(pat) = finder.pat {
498+
499+
self.suggest_ref_for_dbg_args(expr, place, move_span, err);
500+
501+
// it's useless to suggest inserting `ref` when the span don't comes from local code
502+
if let Some(pat) = finder.pat
503+
&& !move_span.is_dummy()
504+
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
505+
{
498506
*in_pattern = true;
499507
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
500508
if let Some(pat) = finder.parent_pat {
@@ -509,6 +517,59 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
509517
}
510518
}
511519

520+
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
521+
// but here we actually do not check whether the macro name is `dbg!`
522+
// so that we may extend the scope a bit larger to cover more cases
523+
fn suggest_ref_for_dbg_args(
524+
&self,
525+
body: &hir::Expr<'_>,
526+
place: &Place<'tcx>,
527+
move_span: Span,
528+
err: &mut Diag<'infcx>,
529+
) {
530+
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
531+
VarDebugInfoContents::Place(ref p) => p == place,
532+
_ => false,
533+
});
534+
let arg_name = if let Some(var_info) = var_info {
535+
var_info.name
536+
} else {
537+
return;
538+
};
539+
struct MatchArgFinder {
540+
expr_span: Span,
541+
match_arg_span: Option<Span>,
542+
arg_name: Symbol,
543+
}
544+
impl Visitor<'_> for MatchArgFinder {
545+
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
546+
// dbg! is expanded into a match pattern, we need to find the right argument span
547+
if let hir::ExprKind::Match(expr, ..) = &e.kind
548+
&& let hir::ExprKind::Path(hir::QPath::Resolved(
549+
_,
550+
path @ Path { segments: [seg], .. },
551+
)) = &expr.kind
552+
&& seg.ident.name == self.arg_name
553+
&& self.expr_span.source_callsite().contains(expr.span)
554+
{
555+
self.match_arg_span = Some(path.span);
556+
}
557+
hir::intravisit::walk_expr(self, e);
558+
}
559+
}
560+
561+
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
562+
finder.visit_expr(body);
563+
if let Some(macro_arg_span) = finder.match_arg_span {
564+
err.span_suggestion_verbose(
565+
macro_arg_span.shrink_to_lo(),
566+
"consider borrowing instead of transferring ownership",
567+
"&",
568+
Applicability::MachineApplicable,
569+
);
570+
}
571+
}
572+
512573
fn report_use_of_uninitialized(
513574
&self,
514575
mpi: MovePathIndex,

Diff for: tests/ui/borrowck/dbg-issue-120327.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 test_not_macro() -> String {
50+
let a = String::new();
51+
let _b = match a {
52+
tmp => {
53+
eprintln!("dbg: {}", tmp);
54+
tmp
55+
}
56+
};
57+
return a; //~ ERROR use of moved value:
58+
}
59+
60+
fn get_expr(_s: String) {}
61+
62+
fn test() {
63+
let a: String = "".to_string();
64+
let _res = get_expr(dbg!(a));
65+
let _l = a.len(); //~ ERROR borrow of moved value
66+
}
67+
68+
fn main() {}

Diff for: tests/ui/borrowck/dbg-issue-120327.stderr

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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]: use of moved value: `a`
84+
--> $DIR/dbg-issue-120327.rs:57:12
85+
|
86+
LL | let a = String::new();
87+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
88+
LL | let _b = match a {
89+
LL | tmp => {
90+
| --- value moved here
91+
...
92+
LL | return a;
93+
| ^ value used here after move
94+
|
95+
help: borrow this binding in the pattern to avoid moving the value
96+
|
97+
LL | ref tmp => {
98+
| +++
99+
100+
error[E0382]: borrow of moved value: `a`
101+
--> $DIR/dbg-issue-120327.rs:65:14
102+
|
103+
LL | let a: String = "".to_string();
104+
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
105+
LL | let _res = get_expr(dbg!(a));
106+
| ------- value moved here
107+
LL | let _l = a.len();
108+
| ^ value borrowed here after move
109+
|
110+
help: consider borrowing instead of transferring ownership
111+
|
112+
LL | let _res = get_expr(dbg!(&a));
113+
| +
114+
115+
error: aborting due to 7 previous errors
116+
117+
For more information about this error, try `rustc --explain E0382`.

Diff for: 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)