Skip to content

Commit e216c00

Browse files
committed
Suggest a borrow when using dbg
1 parent b381d3a commit e216c00

File tree

4 files changed

+230
-9
lines changed

4 files changed

+230
-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::{
@@ -29,11 +30,13 @@ use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
2930
use rustc_span::def_id::LocalDefId;
3031
use rustc_span::hygiene::DesugaringKind;
3132
use rustc_span::symbol::{kw, sym, Ident};
33+
use rustc_span::FileName;
3234
use rustc_span::{BytePos, Span, Symbol};
3335
use rustc_trait_selection::infer::InferCtxtExt;
3436
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
3537
use rustc_trait_selection::traits::ObligationCtxt;
3638
use std::iter;
39+
use std::path::PathBuf;
3740

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

477557
fn report_use_of_uninitialized(

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

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
26+
27+
macro_rules! my_dbg {
28+
() => {
29+
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
30+
};
31+
($val:expr $(,)?) => {
32+
match $val {
33+
tmp => {
34+
eprintln!("[{}:{}:{}] {} = {:#?}",
35+
file!(), line!(), column!(), stringify!($val), &tmp);
36+
tmp
37+
}
38+
}
39+
};
40+
($($val:expr),+ $(,)?) => {
41+
($(my_dbg!($val)),+,)
42+
};
43+
}
44+
45+
46+
fn test_my_dbg() -> String {
47+
let b: String = "".to_string();
48+
my_dbg!(b, 1);
49+
return b; //~ ERROR use of moved value:
50+
}
51+
52+
fn main() {}
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
error[E0382]: use of moved value: `a`
2+
--> $DIR/issue-120327-dbg.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/issue-120327-dbg.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/issue-120327-dbg.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/issue-120327-dbg.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/issue-120327-dbg.rs:49: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: aborting due to 5 previous errors
84+
85+
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)