Skip to content

Commit 0fb0025

Browse files
committed
Auto merge of #78662 - sexxi-goose:add_expr_id_to_delegate, r=nikomatsakis
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 r? `@ghost`
2 parents f2bbdd0 + c9d9359 commit 0fb0025

File tree

7 files changed

+118
-71
lines changed

7 files changed

+118
-71
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+51-32
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

+50-22
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,31 @@ 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 parameter `diag_expr_id` indicates the HIR id that ought to be used for
33+
// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
34+
// id will be the id of the expression `expr` but the place itself will have
35+
// the id of the binding in the pattern `pat`.
36+
fn consume(
37+
&mut self,
38+
place_with_id: &PlaceWithHirId<'tcx>,
39+
diag_expr_id: hir::HirId,
40+
mode: ConsumeMode,
41+
);
3242

3343
// 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>);
44+
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
45+
fn borrow(
46+
&mut self,
47+
place_with_id: &PlaceWithHirId<'tcx>,
48+
diag_expr_id: hir::HirId,
49+
bk: ty::BorrowKind,
50+
);
51+
52+
// The path at `assignee_place` is being assigned to.
53+
// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
54+
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
3855
}
3956

4057
#[derive(Copy, Clone, PartialEq, Debug)]
@@ -116,11 +133,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
116133
self.mc.tcx()
117134
}
118135

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

122139
let mode = copy_or_move(&self.mc, place_with_id);
123-
self.delegate.consume(place_with_id, mode);
140+
self.delegate.consume(place_with_id, diag_expr_id, mode);
124141
}
125142

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

135152
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
136-
self.delegate_consume(&place_with_id);
153+
self.delegate_consume(&place_with_id, place_with_id.hir_id);
137154
self.walk_expr(expr);
138155
}
139156

140157
fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
141158
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
142-
self.delegate.mutate(&place_with_id);
159+
self.delegate.mutate(&place_with_id, place_with_id.hir_id);
143160
self.walk_expr(expr);
144161
}
145162

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

149166
let place_with_id = return_if_err!(self.mc.cat_expr(expr));
150-
self.delegate.borrow(&place_with_id, bk);
167+
self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
151168

152169
self.walk_expr(expr)
153170
}
@@ -404,7 +421,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
404421
with_field.ty(self.tcx(), substs),
405422
ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
406423
);
407-
self.delegate_consume(&field_place);
424+
self.delegate_consume(&field_place, field_place.hir_id);
408425
}
409426
}
410427
}
@@ -436,7 +453,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
436453
adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
437454
// Creating a closure/fn-pointer or unsizing consumes
438455
// the input and stores it into the resulting rvalue.
439-
self.delegate_consume(&place_with_id);
456+
self.delegate_consume(&place_with_id, place_with_id.hir_id);
440457
}
441458

442459
adjustment::Adjust::Deref(None) => {}
@@ -448,7 +465,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
448465
// this is an autoref of `x`.
449466
adjustment::Adjust::Deref(Some(ref deref)) => {
450467
let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
451-
self.delegate.borrow(&place_with_id, bk);
468+
self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
452469
}
453470

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

477494
match *autoref {
478495
adjustment::AutoBorrow::Ref(_, m) => {
479-
self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m.into()));
496+
self.delegate.borrow(
497+
base_place,
498+
base_place.hir_id,
499+
ty::BorrowKind::from_mutbl(m.into()),
500+
);
480501
}
481502

482503
adjustment::AutoBorrow::RawPtr(m) => {
483504
debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place);
484505

485-
self.delegate.borrow(base_place, ty::BorrowKind::from_mutbl(m));
506+
self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m));
486507
}
487508
}
488509
}
@@ -525,19 +546,22 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
525546
// binding being produced.
526547
let def = Res::Local(canonical_id);
527548
if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
528-
delegate.mutate(binding_place);
549+
delegate.mutate(binding_place, binding_place.hir_id);
529550
}
530551

531552
// It is also a borrow or copy/move of the value being matched.
553+
// In a cases of pattern like `let pat = upvar`, don't use the span
554+
// of the pattern, as this just looks confusing, instead use the span
555+
// of the discriminant.
532556
match bm {
533557
ty::BindByReference(m) => {
534558
let bk = ty::BorrowKind::from_mutbl(m);
535-
delegate.borrow(place, bk);
559+
delegate.borrow(place, discr_place.hir_id, bk);
536560
}
537561
ty::BindByValue(..) => {
538-
let mode = copy_or_move(mc, place);
562+
let mode = copy_or_move(mc, &place);
539563
debug!("walk_pat binding consuming pat");
540-
delegate.consume(place, mode);
564+
delegate.consume(place, discr_place.hir_id, mode);
541565
}
542566
}
543567
}
@@ -564,10 +588,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
564588
match upvar_capture {
565589
ty::UpvarCapture::ByValue(_) => {
566590
let mode = copy_or_move(&self.mc, &captured_place);
567-
self.delegate.consume(&captured_place, mode);
591+
self.delegate.consume(&captured_place, captured_place.hir_id, mode);
568592
}
569593
ty::UpvarCapture::ByRef(upvar_borrow) => {
570-
self.delegate.borrow(&captured_place, upvar_borrow.kind);
594+
self.delegate.borrow(
595+
&captured_place,
596+
captured_place.hir_id,
597+
upvar_borrow.kind,
598+
);
571599
}
572600
}
573601
}

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

+1-1
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

+3-3
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
115115
}
116116

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

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

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

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

+7-7
Original file line numberDiff line numberDiff line change
@@ -1957,28 +1957,28 @@ struct MutatePairDelegate<'a, 'tcx> {
19571957
}
19581958

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

1962-
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, bk: ty::BorrowKind) {
1962+
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
19631963
if let ty::BorrowKind::MutBorrow = bk {
19641964
if let PlaceBase::Local(id) = cmt.place.base {
19651965
if Some(id) == self.hir_id_low {
1966-
self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
1966+
self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
19671967
}
19681968
if Some(id) == self.hir_id_high {
1969-
self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
1969+
self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
19701970
}
19711971
}
19721972
}
19731973
}
19741974

1975-
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>) {
1975+
fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
19761976
if let PlaceBase::Local(id) = cmt.place.base {
19771977
if Some(id) == self.hir_id_low {
1978-
self.span_low = Some(self.cx.tcx.hir().span(cmt.hir_id))
1978+
self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
19791979
}
19801980
if Some(id) == self.hir_id_high {
1981-
self.span_high = Some(self.cx.tcx.hir().span(cmt.hir_id))
1981+
self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
19821982
}
19831983
}
19841984
}

0 commit comments

Comments
 (0)