Skip to content

Commit 1f53754

Browse files
committed
Provide diagnostic suggestion in ExprUseVisitor Delegate
The [Delegate trait](https://github.com/rust-lang/rust/blob/981346fc07dd5ef414c5b1b21999f7604cece006/compiler/rustc_typeck/src/expr_use_visitor.rs#L28-L38) currently use `PlaceWithHirId` which is composed of Hir `Place` and the corresponding expression id. Even though this is an accurate way of expressing how a Place is used, it can cause confusion during diagnostics. Eg: ``` let arr : [String; 5]; let [a, ...] = arr; ^^^ E1 ^^^ = ^^E2^^ ``` Here `arr` is moved because of the binding created E1. However, when we point to E1 in diagnostics with the message `arr` was moved, it can be confusing. Rather we would like to report E2 to the user. Closes: rust-lang/project-rfc-2229#20
1 parent c4fe25d commit 1f53754

File tree

7 files changed

+125
-71
lines changed

7 files changed

+125
-71
lines changed

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
279279
fn adjust_upvar_borrow_kind_for_consume(
280280
&mut self,
281281
place_with_id: &PlaceWithHirId<'tcx>,
282+
diag_expr_id: hir::HirId,
282283
mode: euv::ConsumeMode,
283284
) {
284285
debug!(
285-
"adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, mode={:?})",
286-
place_with_id, mode
286+
"adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
287+
place_with_id, diag_expr_id, mode
287288
);
288289

289290
// we only care about moves
@@ -303,7 +304,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
303304

304305
debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id);
305306

306-
let usage_span = tcx.hir().span(place_with_id.hir_id);
307+
let usage_span = tcx.hir().span(diag_expr_id);
307308

308309
// To move out of an upvar, this must be a FnOnce closure
309310
self.adjust_closure_kind(
@@ -313,14 +314,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
313314
var_name(tcx, upvar_id.var_path.hir_id),
314315
);
315316

316-
// In a case like `let pat = upvar`, don't use the span
317-
// of the pattern, as this just looks confusing.
318-
let by_value_span = match tcx.hir().get(place_with_id.hir_id) {
319-
hir::Node::Pat(_) => None,
320-
_ => Some(usage_span),
321-
};
322-
323-
let new_capture = ty::UpvarCapture::ByValue(by_value_span);
317+
let new_capture = ty::UpvarCapture::ByValue(Some(usage_span));
324318
match self.adjust_upvar_captures.entry(upvar_id) {
325319
Entry::Occupied(mut e) => {
326320
match e.get() {
@@ -345,8 +339,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
345339
/// Indicates that `place_with_id` is being directly mutated (e.g., assigned
346340
/// to). If the place is based on a by-ref upvar, this implies that
347341
/// the upvar must be borrowed using an `&mut` borrow.
348-
fn adjust_upvar_borrow_kind_for_mut(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
349-
debug!("adjust_upvar_borrow_kind_for_mut(place_with_id={:?})", place_with_id);
342+
fn adjust_upvar_borrow_kind_for_mut(
343+
&mut self,
344+
place_with_id: &PlaceWithHirId<'tcx>,
345+
diag_expr_id: hir::HirId,
346+
) {
347+
debug!(
348+
"adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})",
349+
place_with_id, diag_expr_id
350+
);
350351

351352
if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
352353
let mut borrow_kind = ty::MutBorrow;
@@ -362,16 +363,19 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
362363
_ => (),
363364
}
364365
}
365-
self.adjust_upvar_deref(
366-
upvar_id,
367-
self.fcx.tcx.hir().span(place_with_id.hir_id),
368-
borrow_kind,
369-
);
366+
self.adjust_upvar_deref(upvar_id, self.fcx.tcx.hir().span(diag_expr_id), borrow_kind);
370367
}
371368
}
372369

373-
fn adjust_upvar_borrow_kind_for_unique(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
374-
debug!("adjust_upvar_borrow_kind_for_unique(place_with_id={:?})", place_with_id);
370+
fn adjust_upvar_borrow_kind_for_unique(
371+
&mut self,
372+
place_with_id: &PlaceWithHirId<'tcx>,
373+
diag_expr_id: hir::HirId,
374+
) {
375+
debug!(
376+
"adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})",
377+
place_with_id, diag_expr_id
378+
);
375379

376380
if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
377381
if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
@@ -381,7 +385,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
381385
// for a borrowed pointer to be unique, its base must be unique
382386
self.adjust_upvar_deref(
383387
upvar_id,
384-
self.fcx.tcx.hir().span(place_with_id.hir_id),
388+
self.fcx.tcx.hir().span(diag_expr_id),
385389
ty::UniqueImmBorrow,
386390
);
387391
}
@@ -500,29 +504,44 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
500504
}
501505

502506
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
503-
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: euv::ConsumeMode) {
504-
debug!("consume(place_with_id={:?},mode={:?})", place_with_id, mode);
505-
self.adjust_upvar_borrow_kind_for_consume(place_with_id, mode);
507+
fn consume(
508+
&mut self,
509+
place_with_id: &PlaceWithHirId<'tcx>,
510+
diag_expr_id: hir::HirId,
511+
mode: euv::ConsumeMode,
512+
) {
513+
debug!(
514+
"consume(place_with_id={:?}, diag_expr_id={:?}, mode={:?})",
515+
place_with_id, diag_expr_id, mode
516+
);
517+
self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id, mode);
506518
}
507519

508-
fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
509-
debug!("borrow(place_with_id={:?}, bk={:?})", place_with_id, bk);
520+
fn borrow(
521+
&mut self,
522+
place_with_id: &PlaceWithHirId<'tcx>,
523+
diag_expr_id: hir::HirId,
524+
bk: ty::BorrowKind,
525+
) {
526+
debug!(
527+
"borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})",
528+
place_with_id, diag_expr_id, bk
529+
);
510530

511531
match bk {
512532
ty::ImmBorrow => {}
513533
ty::UniqueImmBorrow => {
514-
self.adjust_upvar_borrow_kind_for_unique(place_with_id);
534+
self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
515535
}
516536
ty::MutBorrow => {
517-
self.adjust_upvar_borrow_kind_for_mut(place_with_id);
537+
self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
518538
}
519539
}
520540
}
521541

522-
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>) {
523-
debug!("mutate(assignee_place={:?})", assignee_place);
524-
525-
self.adjust_upvar_borrow_kind_for_mut(assignee_place);
542+
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
543+
debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id);
544+
self.adjust_upvar_borrow_kind_for_mut(assignee_place, diag_expr_id);
526545
}
527546
}
528547

compiler/rustc_typeck/src/expr_use_visitor.rs

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,38 @@ use rustc_span::Span;
2727
/// employing the ExprUseVisitor.
2828
pub trait Delegate<'tcx> {
2929
// The value found at `place` is either copied or moved, depending
30-
// on mode.
31-
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, mode: ConsumeMode);
30+
// on mode. Where `diag_expr_id` is the id used for diagnostics for `place`.
31+
//
32+
// The reson for a separate expr_id for diagonostics is to support cases
33+
// like `let pat = upvar`, in such scenarios reporting the pattern (lhs)
34+
// looks confusing. Instead we prefer to report the discriminant (rhs)
35+
fn consume(
36+
&mut self,
37+
place_with_id: &PlaceWithHirId<'tcx>,
38+
diag_expr_id: hir::HirId,
39+
mode: ConsumeMode,
40+
);
3241

3342
// The value found at `place` is being borrowed with kind `bk`.
34-
fn borrow(&mut self, place_with_id: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind);
35-
36-
// The path at `place_with_id` is being assigned to.
37-
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>);
43+
// `diag_expr_id` is the id used for diagnostics for `place`.
44+
//
45+
// The reson for a separate expr_id for diagonostics is to support cases
46+
// like `let pat = upvar`, in such scenarios reporting the pattern (lhs)
47+
// looks confusing. Instead we prefer to report the discriminant (rhs)
48+
fn borrow(
49+
&mut self,
50+
place_with_id: &PlaceWithHirId<'tcx>,
51+
diag_expr_id: hir::HirId,
52+
bk: ty::BorrowKind,
53+
);
54+
55+
// The path at `assignee_place` is being assigned to.
56+
// `diag_expr_id` is the id used for diagnostics for `place`.
57+
//
58+
// The reson for a separate expr_id for diagonostics is to support cases
59+
// like `let pat = upvar`, in such scenarios reporting the pattern (lhs)
60+
// looks confusing. Instead we prefer to report the discriminant (rhs)
61+
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
3862
}
3963

4064
#[derive(Copy, Clone, PartialEq, Debug)]
@@ -116,11 +140,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
116140
self.mc.tcx()
117141
}
118142

119-
fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>) {
143+
fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
120144
debug!("delegate_consume(place_with_id={:?})", place_with_id);
121145

122146
let mode = copy_or_move(&self.mc, place_with_id);
123-
self.delegate.consume(place_with_id, mode);
147+
self.delegate.consume(place_with_id, diag_expr_id, mode);
124148
}
125149

126150
fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
@@ -133,21 +157,21 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
133157
debug!("consume_expr(expr={:?})", expr);
134158

135159
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
136-
self.delegate_consume(&place_with_id);
160+
self.delegate_consume(&place_with_id, place_with_id.hir_id);
137161
self.walk_expr(expr);
138162
}
139163

140164
fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
141165
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
142-
self.delegate.mutate(&place_with_id);
166+
self.delegate.mutate(&place_with_id, place_with_id.hir_id);
143167
self.walk_expr(expr);
144168
}
145169

146170
fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) {
147171
debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
148172

149173
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
150-
self.delegate.borrow(&place_with_id, bk);
174+
self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
151175

152176
self.walk_expr(expr)
153177
}
@@ -404,7 +428,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
404428
with_field.ty(self.tcx(), substs),
405429
ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
406430
);
407-
self.delegate_consume(&field_place);
431+
self.delegate_consume(&field_place, field_place.hir_id);
408432
}
409433
}
410434
}
@@ -436,7 +460,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
436460
adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
437461
// Creating a closure/fn-pointer or unsizing consumes
438462
// the input and stores it into the resulting rvalue.
439-
self.delegate_consume(&place_with_id);
463+
self.delegate_consume(&place_with_id, place_with_id.hir_id);
440464
}
441465

442466
adjustment::Adjust::Deref(None) => {}
@@ -448,7 +472,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
448472
// this is an autoref of `x`.
449473
adjustment::Adjust::Deref(Some(ref deref)) => {
450474
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
451-
self.delegate.borrow(&place_with_id, bk);
475+
self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
452476
}
453477

454478
adjustment::Adjust::Borrow(ref autoref) => {
@@ -476,13 +500,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
476500

477501
match *autoref {
478502
adjustment::AutoBorrow::Ref(_, m) => {
479-
self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m.into()));
503+
self.delegate.borrow(
504+
base_place,
505+
base_place.hir_id,
506+
ty::BorrowKind::from_mutbl(m.into()),
507+
);
480508
}
481509

482510
adjustment::AutoBorrow::RawPtr(m) => {
483511
debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place);
484512

485-
self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m));
513+
self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m));
486514
}
487515
}
488516
}
@@ -525,19 +553,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
525553
// binding being produced.
526554
let def = Res::Local(canonical_id);
527555
if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
528-
delegate.mutate(binding_place);
556+
delegate.mutate(binding_place, binding_place.hir_id);
529557
}
530558

531559
// It is also a borrow or copy/move of the value being matched.
560+
// In a cases of pattern like `let pat = upvar`, don't use the span
561+
// of the pattern, as this just looks confusing, instead use the span
562+
// of the discriminant.
532563
match bm {
533564
ty::BindByReference(m) => {
534565
let bk = ty::BorrowKind::from_mutbl(m);
535-
delegate.borrow(place, bk);
566+
delegate.borrow(place, discr_place.hir_id, bk);
536567
}
537568
ty::BindByValue(..) => {
538-
let mode = copy_or_move(mc, place);
569+
let mode = copy_or_move(mc, &place);
539570
debug!("walk_pat binding consuming pat");
540-
delegate.consume(place, mode);
571+
delegate.consume(place, discr_place.hir_id, mode);
541572
}
542573
}
543574
}
@@ -564,10 +595,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
564595
match upvar_capture {
565596
ty::UpvarCapture::ByValue(_) => {
566597
let mode = copy_or_move(&self.mc, &captured_place);
567-
self.delegate.consume(&captured_place, mode);
598+
self.delegate.consume(&captured_place, captured_place.hir_id, mode);
568599
}
569600
ty::UpvarCapture::ByRef(upvar_borrow) => {
570-
self.delegate.borrow(&captured_place, upvar_borrow.kind);
601+
self.delegate.borrow(
602+
&captured_place,
603+
captured_place.hir_id,
604+
upvar_borrow.kind,
605+
);
571606
}
572607
}
573608
}

src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ LL | fn arr_box_by_move(x: Box<[String; 3]>) {
7575
LL | let f = || {
7676
| -- value moved into closure here
7777
LL | let [y, z @ ..] = *x;
78-
| - variable moved due to use in closure
78+
| -- variable moved due to use in closure
7979
LL | };
8080
LL | &x;
8181
| ^^ value borrowed here after move

src/tools/clippy/clippy_lints/src/escape.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
116116
}
117117

118118
impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
119-
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, mode: ConsumeMode) {
119+
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, mode: ConsumeMode) {
120120
if cmt.place.projections.is_empty() {
121121
if let PlaceBase::Local(lid) = cmt.place.base {
122122
if let ConsumeMode::Move = mode {
@@ -136,15 +136,15 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
136136
}
137137
}
138138

139-
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: ty::BorrowKind) {
139+
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
140140
if cmt.place.projections.is_empty() {
141141
if let PlaceBase::Local(lid) = cmt.place.base {
142142
self.set.remove(&lid);
143143
}
144144
}
145145
}
146146

147-
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
147+
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
148148
if cmt.place.projections.is_empty() {
149149
let map = &self.cx.tcx.hir();
150150
if is_argument(*map, cmt.hir_id) {

src/tools/clippy/clippy_lints/src/loops.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,28 +1694,28 @@ struct MutatePairDelegate<'a, 'tcx> {
16941694
}
16951695

16961696
impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
1697-
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: ConsumeMode) {}
1697+
fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}
16981698

1699-
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
1699+
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
17001700
if let ty::BorrowKind::MutBorrow = bk {
17011701
if let PlaceBase::Local(id) = cmt.place.base {
17021702
if Some(id) == self.hir_id_low {
1703-
self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
1703+
self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
17041704
}
17051705
if Some(id) == self.hir_id_high {
1706-
self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
1706+
self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
17071707
}
17081708
}
17091709
}
17101710
}
17111711

1712-
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
1712+
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
17131713
if let PlaceBase::Local(id) = cmt.place.base {
17141714
if Some(id) == self.hir_id_low {
1715-
self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
1715+
self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
17161716
}
17171717
if Some(id) == self.hir_id_high {
1718-
self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
1718+
self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
17191719
}
17201720
}
17211721
}

0 commit comments

Comments
 (0)