]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/expr_use_visitor.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / compiler / rustc_typeck / src / expr_use_visitor.rs
CommitLineData
9fa01778 1//! A different sort of visitor for walking fn bodies. Unlike the
1a4d82fc
JJ
2//! normal visitor, which just walks the entire body in one shot, the
3//! `ExprUseVisitor` determines how expressions are being used.
4
1a4d82fc 5pub use self::ConsumeMode::*;
1a4d82fc 6
60c5eb7d 7// Export these here so that Clippy can use them.
6a06907d 8pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
60c5eb7d 9
6a06907d 10use rustc_data_structures::fx::FxIndexMap;
dfeec247
XL
11use rustc_hir as hir;
12use rustc_hir::def::Res;
f9f354fc 13use rustc_hir::def_id::LocalDefId;
dfeec247 14use rustc_hir::PatKind;
3dfed10e 15use rustc_index::vec::Idx;
74b04a01 16use rustc_infer::infer::InferCtxt;
3dfed10e 17use rustc_middle::hir::place::ProjectionKind;
6a06907d 18use rustc_middle::mir::FakeReadCause;
ba9703b0 19use rustc_middle::ty::{self, adjustment, TyCtxt};
3dfed10e 20use rustc_target::abi::VariantIdx;
60c5eb7d
XL
21
22use crate::mem_categorization as mc;
1a4d82fc
JJ
23
24///////////////////////////////////////////////////////////////////////////
25// The Delegate trait
26
27/// This trait defines the callbacks you can expect to receive when
28/// employing the ExprUseVisitor.
29pub trait Delegate<'tcx> {
60c5eb7d 30 // The value found at `place` is either copied or moved, depending
29967ef6
XL
31 // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
32 //
33 // The parameter `diag_expr_id` indicates the HIR id that ought to be used for
34 // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
35 // id will be the id of the expression `expr` but the place itself will have
36 // the id of the binding in the pattern `pat`.
37 fn consume(
38 &mut self,
39 place_with_id: &PlaceWithHirId<'tcx>,
40 diag_expr_id: hir::HirId,
41 mode: ConsumeMode,
42 );
1a4d82fc 43
60c5eb7d 44 // The value found at `place` is being borrowed with kind `bk`.
29967ef6
XL
45 // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
46 fn borrow(
47 &mut self,
48 place_with_id: &PlaceWithHirId<'tcx>,
49 diag_expr_id: hir::HirId,
50 bk: ty::BorrowKind,
51 );
52
53 // The path at `assignee_place` is being assigned to.
54 // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
55 fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
6a06907d
XL
56
57 // The `place` should be a fake read because of specified `cause`.
58 fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
1a4d82fc
JJ
59}
60
c34b1796 61#[derive(Copy, Clone, PartialEq, Debug)]
1a4d82fc 62pub enum ConsumeMode {
dfeec247
XL
63 Copy, // reference to x where x has a type that copies
64 Move, // reference to x where x has a type that moves
1a4d82fc
JJ
65}
66
c34b1796 67#[derive(Copy, Clone, PartialEq, Debug)]
1a4d82fc
JJ
68pub enum MutateMode {
69 Init,
70 JustWrite, // x = y
71 WriteAndRead, // x += y
72}
73
1a4d82fc
JJ
74///////////////////////////////////////////////////////////////////////////
75// The ExprUseVisitor type
76//
041b39d2 77// This is the code that actually walks the tree.
dc9dc135
XL
78pub struct ExprUseVisitor<'a, 'tcx> {
79 mc: mc::MemCategorizationContext<'a, 'tcx>,
fc512014 80 body_owner: LocalDefId,
0531ce1d 81 delegate: &'a mut dyn Delegate<'tcx>,
1a4d82fc
JJ
82}
83
041b39d2 84// If the MC results in an error, it's because the type check
1a4d82fc
JJ
85// failed (or will fail, when the error is uncovered and reported
86// during writeback). In this case, we just ignore this part of the
87// code.
88//
89// Note that this macro appears similar to try!(), but, unlike try!(),
90// it does not propagate the error.
91macro_rules! return_if_err {
dfeec247 92 ($inp: expr) => {
1a4d82fc
JJ
93 match $inp {
94 Ok(v) => v,
c1a9b12d
SL
95 Err(()) => {
96 debug!("mc reported err");
dfeec247 97 return;
c1a9b12d 98 }
1a4d82fc 99 }
dfeec247 100 };
1a4d82fc
JJ
101}
102
dc9dc135 103impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
abe05a73
XL
104 /// Creates the ExprUseVisitor, configuring it with the various options provided:
105 ///
106 /// - `delegate` -- who receives the callbacks
107 /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
3dfed10e 108 /// - `typeck_results` --- typeck results for the code being analyzed
dc9dc135 109 pub fn new(
dc9dc135
XL
110 delegate: &'a mut (dyn Delegate<'tcx> + 'a),
111 infcx: &'a InferCtxt<'a, 'tcx>,
f9f354fc 112 body_owner: LocalDefId,
dc9dc135 113 param_env: ty::ParamEnv<'tcx>,
3dfed10e 114 typeck_results: &'a ty::TypeckResults<'tcx>,
dc9dc135 115 ) -> Self {
a7813a04 116 ExprUseVisitor {
3dfed10e 117 mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results),
fc512014 118 body_owner,
7cac9316 119 delegate,
a7813a04 120 }
1a4d82fc
JJ
121 }
122
dfeec247 123 pub fn consume_body(&mut self, body: &hir::Body<'_>) {
cc61c64b
XL
124 debug!("consume_body(body={:?})", body);
125
dfeec247 126 for param in body.params {
e1599b0c
XL
127 let param_ty = return_if_err!(self.mc.pat_ty_adjusted(&param.pat));
128 debug!("consume_body: param_ty = {:?}", param_ty);
1a4d82fc 129
60c5eb7d 130 let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
1a4d82fc 131
60c5eb7d 132 self.walk_irrefutable_pat(&param_place, &param.pat);
1a4d82fc 133 }
32a655c1
SL
134
135 self.consume_expr(&body.value);
1a4d82fc
JJ
136 }
137
dc9dc135 138 fn tcx(&self) -> TyCtxt<'tcx> {
60c5eb7d 139 self.mc.tcx()
1a4d82fc
JJ
140 }
141
29967ef6 142 fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
f035d41b 143 debug!("delegate_consume(place_with_id={:?})", place_with_id);
85aaf69f 144
f035d41b 145 let mode = copy_or_move(&self.mc, place_with_id);
29967ef6 146 self.delegate.consume(place_with_id, diag_expr_id, mode);
1a4d82fc
JJ
147 }
148
dfeec247 149 fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
85aaf69f 150 for expr in exprs {
7453a54e 151 self.consume_expr(&expr);
1a4d82fc
JJ
152 }
153 }
154
dfeec247 155 pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
62682a34 156 debug!("consume_expr(expr={:?})", expr);
1a4d82fc 157
f035d41b 158 let place_with_id = return_if_err!(self.mc.cat_expr(expr));
29967ef6 159 self.delegate_consume(&place_with_id, place_with_id.hir_id);
1a4d82fc
JJ
160 self.walk_expr(expr);
161 }
162
dfeec247 163 fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
f035d41b 164 let place_with_id = return_if_err!(self.mc.cat_expr(expr));
29967ef6 165 self.delegate.mutate(&place_with_id, place_with_id.hir_id);
1a4d82fc
JJ
166 self.walk_expr(expr);
167 }
168
dfeec247 169 fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) {
e74abb32 170 debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
1a4d82fc 171
f035d41b 172 let place_with_id = return_if_err!(self.mc.cat_expr(expr));
29967ef6 173 self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
1a4d82fc 174
1a4d82fc
JJ
175 self.walk_expr(expr)
176 }
177
dfeec247 178 fn select_from_expr(&mut self, expr: &hir::Expr<'_>) {
1a4d82fc
JJ
179 self.walk_expr(expr)
180 }
181
dfeec247 182 pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
62682a34 183 debug!("walk_expr(expr={:?})", expr);
1a4d82fc
JJ
184
185 self.walk_adjustment(expr);
186
e74abb32 187 match expr.kind {
dfeec247 188 hir::ExprKind::Path(_) => {}
1a4d82fc 189
dfeec247 190 hir::ExprKind::Type(ref subexpr, _) => self.walk_expr(subexpr),
9cc50fc6 191
6a06907d 192 hir::ExprKind::Unary(hir::UnOp::Deref, ref base) => {
dfeec247 193 // *base
e74abb32 194 self.select_from_expr(base);
1a4d82fc
JJ
195 }
196
dfeec247
XL
197 hir::ExprKind::Field(ref base, _) => {
198 // base.f
e74abb32 199 self.select_from_expr(base);
1a4d82fc
JJ
200 }
201
dfeec247
XL
202 hir::ExprKind::Index(ref lhs, ref rhs) => {
203 // lhs[rhs]
e74abb32
XL
204 self.select_from_expr(lhs);
205 self.consume_expr(rhs);
1a4d82fc
JJ
206 }
207
dfeec247
XL
208 hir::ExprKind::Call(ref callee, ref args) => {
209 // callee(args)
210 self.consume_expr(callee);
1a4d82fc
JJ
211 self.consume_exprs(args);
212 }
213
f035d41b 214 hir::ExprKind::MethodCall(.., ref args, _) => {
dfeec247 215 // callee.m(args)
1a4d82fc
JJ
216 self.consume_exprs(args);
217 }
218
8faf50e0 219 hir::ExprKind::Struct(_, ref fields, ref opt_with) => {
9e0c209e 220 self.walk_struct_expr(fields, opt_with);
1a4d82fc
JJ
221 }
222
8faf50e0 223 hir::ExprKind::Tup(ref exprs) => {
1a4d82fc
JJ
224 self.consume_exprs(exprs);
225 }
226
5869c6ff
XL
227 hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => {
228 self.consume_expr(&cond_expr);
229 self.consume_expr(&then_expr);
230 if let Some(ref else_expr) = *opt_else_expr {
231 self.consume_expr(&else_expr);
232 }
233 }
234
dfeec247 235 hir::ExprKind::Match(ref discr, arms, _) => {
60c5eb7d 236 let discr_place = return_if_err!(self.mc.cat_expr(&discr));
6a06907d
XL
237
238 // Matching should not always be considered a use of the place, hence
239 // discr does not necessarily need to be borrowed.
240 // We only want to borrow discr if the pattern contain something other
241 // than wildcards.
242 let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
243 let mut needs_to_be_read = false;
244 for arm in arms.iter() {
245 return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| {
246 match &pat.kind {
247 PatKind::Binding(.., opt_sub_pat) => {
248 // If the opt_sub_pat is None, than the binding does not count as
249 // a wildcard for the purpose of borrowing discr.
250 if opt_sub_pat.is_none() {
251 needs_to_be_read = true;
252 }
253 }
254 PatKind::TupleStruct(..)
255 | PatKind::Path(..)
256 | PatKind::Struct(..)
257 | PatKind::Tuple(..) => {
258 // If the PatKind is a TupleStruct, Struct or Tuple then we want to check
259 // whether the Variant is a MultiVariant or a SingleVariant. We only want
260 // to borrow discr if it is a MultiVariant.
261 // If it is a SingleVariant and creates a binding we will handle that when
262 // this callback gets called again.
263 if let ty::Adt(def, _) = place.place.base_ty.kind() {
264 if def.variants.len() > 1 {
265 needs_to_be_read = true;
266 }
267 }
268 }
269 PatKind::Lit(_) => {
270 // If the PatKind is a Lit then we want
271 // to borrow discr.
272 needs_to_be_read = true;
273 }
274 _ => {}
275 }
276 }));
277 }
278
279 if needs_to_be_read {
280 self.borrow_expr(&discr, ty::ImmBorrow);
281 } else {
282 self.delegate.fake_read(
283 discr_place.place.clone(),
284 FakeReadCause::ForMatchedPlace,
285 discr_place.hir_id,
286 );
287
288 // We always want to walk the discriminant. We want to make sure, for instance,
289 // that the discriminant has been initialized.
290 self.walk_expr(&discr);
291 }
1a4d82fc
JJ
292
293 // treatment of the discriminant is handled while walking the arms.
85aaf69f 294 for arm in arms {
60c5eb7d 295 self.walk_arm(&discr_place, arm);
1a4d82fc
JJ
296 }
297 }
298
8faf50e0 299 hir::ExprKind::Array(ref exprs) => {
1a4d82fc
JJ
300 self.consume_exprs(exprs);
301 }
302
dfeec247
XL
303 hir::ExprKind::AddrOf(_, m, ref base) => {
304 // &base
1a4d82fc
JJ
305 // make sure that the thing we are pointing out stays valid
306 // for the lifetime `scope_r` of the resulting ptr:
e74abb32
XL
307 let bk = ty::BorrowKind::from_mutbl(m);
308 self.borrow_expr(&base, bk);
1a4d82fc
JJ
309 }
310
f9f354fc 311 hir::ExprKind::InlineAsm(ref asm) => {
fc512014 312 for (op, _op_sp) in asm.operands {
f9f354fc
XL
313 match op {
314 hir::InlineAsmOperand::In { expr, .. }
315 | hir::InlineAsmOperand::Const { expr, .. }
316 | hir::InlineAsmOperand::Sym { expr, .. } => self.consume_expr(expr),
317 hir::InlineAsmOperand::Out { expr, .. } => {
318 if let Some(expr) = expr {
319 self.mutate_expr(expr);
320 }
321 }
322 hir::InlineAsmOperand::InOut { expr, .. } => {
323 self.mutate_expr(expr);
324 }
325 hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
326 self.consume_expr(in_expr);
327 if let Some(out_expr) = out_expr {
328 self.mutate_expr(out_expr);
329 }
330 }
331 }
332 }
333 }
334
ba9703b0 335 hir::ExprKind::LlvmInlineAsm(ref ia) => {
dfeec247 336 for (o, output) in ia.inner.outputs.iter().zip(ia.outputs_exprs) {
54a0048b
SL
337 if o.is_indirect {
338 self.consume_expr(output);
9cc50fc6 339 } else {
e74abb32 340 self.mutate_expr(output);
9cc50fc6 341 }
1a4d82fc 342 }
60c5eb7d 343 self.consume_exprs(&ia.inputs_exprs);
1a4d82fc
JJ
344 }
345
29967ef6
XL
346 hir::ExprKind::Continue(..)
347 | hir::ExprKind::Lit(..)
348 | hir::ExprKind::ConstBlock(..)
349 | hir::ExprKind::Err => {}
1a4d82fc 350
5869c6ff 351 hir::ExprKind::Loop(ref blk, ..) => {
e74abb32 352 self.walk_block(blk);
1a4d82fc
JJ
353 }
354
8faf50e0 355 hir::ExprKind::Unary(_, ref lhs) => {
e74abb32 356 self.consume_expr(lhs);
1a4d82fc
JJ
357 }
358
8faf50e0 359 hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
e74abb32
XL
360 self.consume_expr(lhs);
361 self.consume_expr(rhs);
1a4d82fc
JJ
362 }
363
8faf50e0 364 hir::ExprKind::Block(ref blk, _) => {
e74abb32 365 self.walk_block(blk);
1a4d82fc
JJ
366 }
367
8faf50e0 368 hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => {
85aaf69f 369 if let Some(ref expr) = *opt_expr {
e74abb32 370 self.consume_expr(expr);
1a4d82fc
JJ
371 }
372 }
373
dfeec247 374 hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
e74abb32
XL
375 self.mutate_expr(lhs);
376 self.consume_expr(rhs);
1a4d82fc
JJ
377 }
378
8faf50e0 379 hir::ExprKind::Cast(ref base, _) => {
e74abb32 380 self.consume_expr(base);
1a4d82fc
JJ
381 }
382
48663c56 383 hir::ExprKind::DropTemps(ref expr) => {
e74abb32 384 self.consume_expr(expr);
48663c56
XL
385 }
386
8faf50e0 387 hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
3dfed10e 388 if self.mc.typeck_results.is_method_call(expr) {
7cac9316
XL
389 self.consume_expr(lhs);
390 } else {
e74abb32 391 self.mutate_expr(lhs);
b039eaaf 392 }
e74abb32 393 self.consume_expr(rhs);
1a4d82fc
JJ
394 }
395
8faf50e0 396 hir::ExprKind::Repeat(ref base, _) => {
e74abb32 397 self.consume_expr(base);
1a4d82fc
JJ
398 }
399
fc512014
XL
400 hir::ExprKind::Closure(..) => {
401 self.walk_captures(expr);
1a4d82fc
JJ
402 }
403
8faf50e0 404 hir::ExprKind::Box(ref base) => {
e74abb32 405 self.consume_expr(base);
1a4d82fc 406 }
ea8adc8c 407
dc9dc135 408 hir::ExprKind::Yield(ref value, _) => {
e74abb32 409 self.consume_expr(value);
ea8adc8c 410 }
1a4d82fc
JJ
411 }
412 }
413
dfeec247 414 fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
e74abb32 415 match stmt.kind {
9fa01778
XL
416 hir::StmtKind::Local(ref local) => {
417 self.walk_local(&local);
418 }
1a4d82fc 419
9fa01778 420 hir::StmtKind::Item(_) => {
e1599b0c 421 // We don't visit nested items in this visitor,
9fa01778 422 // only the fn body we were given.
1a4d82fc
JJ
423 }
424
dfeec247 425 hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
7453a54e 426 self.consume_expr(&expr);
1a4d82fc 427 }
1a4d82fc
JJ
428 }
429 }
430
dfeec247 431 fn walk_local(&mut self, local: &hir::Local<'_>) {
e74abb32
XL
432 if let Some(ref expr) = local.init {
433 // Variable declarations with
434 // initializers are considered
435 // "assigns", which is handled by
436 // `walk_pat`:
437 self.walk_expr(&expr);
60c5eb7d
XL
438 let init_place = return_if_err!(self.mc.cat_expr(&expr));
439 self.walk_irrefutable_pat(&init_place, &local.pat);
1a4d82fc
JJ
440 }
441 }
442
443 /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
444 /// depending on its type.
dfeec247 445 fn walk_block(&mut self, blk: &hir::Block<'_>) {
532ac7d7 446 debug!("walk_block(blk.hir_id={})", blk.hir_id);
1a4d82fc 447
dfeec247 448 for stmt in blk.stmts {
92a42be0 449 self.walk_stmt(stmt);
1a4d82fc
JJ
450 }
451
85aaf69f 452 if let Some(ref tail_expr) = blk.expr {
7453a54e 453 self.consume_expr(&tail_expr);
1a4d82fc
JJ
454 }
455 }
456
dfeec247
XL
457 fn walk_struct_expr(
458 &mut self,
6a06907d 459 fields: &[hir::ExprField<'_>],
dfeec247
XL
460 opt_with: &Option<&'hir hir::Expr<'_>>,
461 ) {
1a4d82fc 462 // Consume the expressions supplying values for each field.
85aaf69f 463 for field in fields {
7453a54e 464 self.consume_expr(&field.expr);
1a4d82fc
JJ
465 }
466
467 let with_expr = match *opt_with {
468 Some(ref w) => &**w,
dfeec247
XL
469 None => {
470 return;
471 }
1a4d82fc
JJ
472 };
473
60c5eb7d 474 let with_place = return_if_err!(self.mc.cat_expr(&with_expr));
1a4d82fc
JJ
475
476 // Select just those fields of the `with`
477 // expression that will actually be used
1b1a35ee 478 match with_place.place.ty().kind() {
b7449926 479 ty::Adt(adt, substs) if adt.is_struct() => {
9e0c209e 480 // Consume those fields of the with expression that are needed.
83c7162d 481 for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
3dfed10e
XL
482 let is_mentioned = fields.iter().any(|f| {
483 self.tcx().field_index(f.hir_id, self.mc.typeck_results) == f_index
484 });
83c7162d 485 if !is_mentioned {
60c5eb7d 486 let field_place = self.mc.cat_projection(
9e0c209e 487 &*with_expr,
60c5eb7d
XL
488 with_place.clone(),
489 with_field.ty(self.tcx(), substs),
3dfed10e 490 ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
9e0c209e 491 );
29967ef6 492 self.delegate_consume(&field_place, field_place.hir_id);
9e0c209e 493 }
1a4d82fc 494 }
1a4d82fc 495 }
9e0c209e
SL
496 _ => {
497 // the base expression should always evaluate to a
498 // struct; however, when EUV is run during typeck, it
499 // may not. This will generate an error earlier in typeck,
500 // so we can just ignore it.
501 if !self.tcx().sess.has_errors() {
dfeec247 502 span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
9e0c209e 503 }
1a4d82fc 504 }
9e0c209e 505 }
1a4d82fc
JJ
506
507 // walk the with expression so that complex expressions
508 // are properly handled.
509 self.walk_expr(with_expr);
1a4d82fc
JJ
510 }
511
512 // Invoke the appropriate delegate calls for anything that gets
513 // consumed or borrowed as part of the automatic adjustment
514 // process.
dfeec247 515 fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
3dfed10e 516 let adjustments = self.mc.typeck_results.expr_adjustments(expr);
f035d41b 517 let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
7cac9316
XL
518 for adjustment in adjustments {
519 debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
c30ab7b3 520 match adjustment.kind {
dfeec247 521 adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => {
9346a6ac
AL
522 // Creating a closure/fn-pointer or unsizing consumes
523 // the input and stores it into the resulting rvalue.
29967ef6 524 self.delegate_consume(&place_with_id, place_with_id.hir_id);
9346a6ac 525 }
c30ab7b3 526
7cac9316
XL
527 adjustment::Adjust::Deref(None) => {}
528
529 // Autoderefs for overloaded Deref calls in fact reference
530 // their receiver. That is, if we have `(*x)` where `x`
531 // is of type `Rc<T>`, then this in fact is equivalent to
532 // `x.deref()`. Since `deref()` is declared with `&self`,
533 // this is an autoref of `x`.
534 adjustment::Adjust::Deref(Some(ref deref)) => {
535 let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
29967ef6 536 self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
1a4d82fc 537 }
1a4d82fc 538
7cac9316 539 adjustment::Adjust::Borrow(ref autoref) => {
f035d41b 540 self.walk_autoref(expr, &place_with_id, autoref);
7cac9316 541 }
1a4d82fc 542 }
f035d41b
XL
543 place_with_id =
544 return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment));
1a4d82fc
JJ
545 }
546 }
547
7cac9316 548 /// Walks the autoref `autoref` applied to the autoderef'd
60c5eb7d 549 /// `expr`. `base_place` is the mem-categorized form of `expr`
7cac9316 550 /// after all relevant autoderefs have occurred.
dfeec247
XL
551 fn walk_autoref(
552 &mut self,
553 expr: &hir::Expr<'_>,
3dfed10e 554 base_place: &PlaceWithHirId<'tcx>,
dfeec247
XL
555 autoref: &adjustment::AutoBorrow<'tcx>,
556 ) {
557 debug!(
558 "walk_autoref(expr.hir_id={} base_place={:?} autoref={:?})",
559 expr.hir_id, base_place, autoref
560 );
1a4d82fc 561
9346a6ac 562 match *autoref {
e74abb32 563 adjustment::AutoBorrow::Ref(_, m) => {
29967ef6
XL
564 self.delegate.borrow(
565 base_place,
566 base_place.hir_id,
567 ty::BorrowKind::from_mutbl(m.into()),
568 );
1a4d82fc 569 }
9346a6ac 570
c30ab7b3 571 adjustment::AutoBorrow::RawPtr(m) => {
dfeec247 572 debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place);
1a4d82fc 573
29967ef6 574 self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m));
e74abb32 575 }
1a4d82fc 576 }
1a4d82fc
JJ
577 }
578
f035d41b 579 fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
6a06907d
XL
580 self.delegate.fake_read(
581 discr_place.place.clone(),
582 FakeReadCause::ForMatchedPlace,
583 discr_place.hir_id,
584 );
60c5eb7d 585 self.walk_pat(discr_place, &arm.pat);
1a4d82fc 586
0bf4aa26
XL
587 if let Some(hir::Guard::If(ref e)) = arm.guard {
588 self.consume_expr(e)
1a4d82fc
JJ
589 }
590
7453a54e 591 self.consume_expr(&arm.body);
1a4d82fc
JJ
592 }
593
9fa01778
XL
594 /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
595 /// let binding, and *not* a match arm or nested pat.)
f035d41b 596 fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
6a06907d
XL
597 self.delegate.fake_read(
598 discr_place.place.clone(),
599 FakeReadCause::ForLet,
600 discr_place.hir_id,
601 );
60c5eb7d 602 self.walk_pat(discr_place, pat);
1a4d82fc
JJ
603 }
604
e74abb32 605 /// The core driver for walking a pattern
f035d41b 606 fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
60c5eb7d 607 debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat);
1a4d82fc 608
8faf50e0 609 let tcx = self.tcx();
fc512014 610 let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
60c5eb7d 611 return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
e74abb32 612 if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
dfeec247 613 debug!("walk_pat: binding place={:?} pat={:?}", place, pat,);
3dfed10e
XL
614 if let Some(bm) =
615 mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
616 {
8faf50e0
XL
617 debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
618
619 // pat_ty: the type of the binding being produced.
620 let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
621 debug!("walk_pat: pat_ty={:?}", pat_ty);
622
623 // Each match binding is effectively an assignment to the
624 // binding being produced.
48663c56 625 let def = Res::Local(canonical_id);
60c5eb7d 626 if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
29967ef6 627 delegate.mutate(binding_place, binding_place.hir_id);
8faf50e0 628 }
5bcae85e 629
8faf50e0 630 // It is also a borrow or copy/move of the value being matched.
29967ef6
XL
631 // In a cases of pattern like `let pat = upvar`, don't use the span
632 // of the pattern, as this just looks confusing, instead use the span
633 // of the discriminant.
8faf50e0
XL
634 match bm {
635 ty::BindByReference(m) => {
e74abb32 636 let bk = ty::BorrowKind::from_mutbl(m);
29967ef6 637 delegate.borrow(place, discr_place.hir_id, bk);
8faf50e0
XL
638 }
639 ty::BindByValue(..) => {
29967ef6 640 let mode = copy_or_move(mc, &place);
8faf50e0 641 debug!("walk_pat binding consuming pat");
29967ef6 642 delegate.consume(place, discr_place.hir_id, mode);
c1a9b12d 643 }
1a4d82fc 644 }
1a4d82fc
JJ
645 }
646 }
647 }));
1a4d82fc
JJ
648 }
649
fc512014
XL
650 /// Handle the case where the current body contains a closure.
651 ///
652 /// When the current body being handled is a closure, then we must make sure that
653 /// - The parent closure only captures Places from the nested closure that are not local to it.
654 ///
655 /// In the following example the closures `c` only captures `p.x`` even though `incr`
656 /// is a capture of the nested closure
657 ///
658 /// ```rust,ignore(cannot-test-this-because-pseduo-code)
659 /// let p = ..;
660 /// let c = || {
661 /// let incr = 10;
662 /// let nested = || p.x += incr;
663 /// }
664 /// ```
665 ///
666 /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
667 /// closure as the DefId.
668 fn walk_captures(&mut self, closure_expr: &hir::Expr<'_>) {
6a06907d
XL
669 fn upvar_is_local_variable(
670 upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
671 upvar_id: &hir::HirId,
672 body_owner_is_closure: bool,
673 ) -> bool {
674 upvars.map(|upvars| !upvars.contains_key(upvar_id)).unwrap_or(body_owner_is_closure)
675 }
676
62682a34 677 debug!("walk_captures({:?})", closure_expr);
1a4d82fc 678
fc512014
XL
679 let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
680 let upvars = self.tcx().upvars_mentioned(self.body_owner);
681
682 // For purposes of this function, generator and closures are equivalent.
5869c6ff
XL
683 let body_owner_is_closure = matches!(
684 self.tcx().type_of(self.body_owner.to_def_id()).kind(),
685 ty::Closure(..) | ty::Generator(..)
686 );
fc512014 687
6a06907d
XL
688 // If we have a nested closure, we want to include the fake reads present in the nested closure.
689 if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
690 for (fake_read, cause, hir_id) in fake_reads.iter() {
691 match fake_read.base {
692 PlaceBase::Upvar(upvar_id) => {
693 if upvar_is_local_variable(
694 upvars,
695 &upvar_id.var_path.hir_id,
696 body_owner_is_closure,
697 ) {
698 // The nested closure might be fake reading the current (enclosing) closure's local variables.
699 // The only places we want to fake read before creating the parent closure are the ones that
700 // are not local to it/ defined by it.
701 //
702 // ```rust,ignore(cannot-test-this-because-pseduo-code)
703 // let v1 = (0, 1);
704 // let c = || { // fake reads: v1
705 // let v2 = (0, 1);
706 // let e = || { // fake reads: v1, v2
707 // let (_, t1) = v1;
708 // let (_, t2) = v2;
709 // }
710 // }
711 // ```
712 // This check is performed when visiting the body of the outermost closure (`c`) and ensures
713 // that we don't add a fake read of v2 in c.
714 continue;
715 }
716 }
717 _ => {
718 bug!(
719 "Do not know how to get HirId out of Rvalue and StaticItem {:?}",
720 fake_read.base
721 );
722 }
723 };
724 self.delegate.fake_read(fake_read.clone(), *cause, *hir_id);
725 }
726 }
727
fc512014
XL
728 if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
729 {
730 for (var_hir_id, min_list) in min_captures.iter() {
731 if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
732 // The nested closure might be capturing the current (enclosing) closure's local variables.
733 // We check if the root variable is ever mentioned within the enclosing closure, if not
734 // then for the current body (if it's a closure) these aren't captures, we will ignore them.
735 continue;
736 }
737 for captured_place in min_list {
738 let place = &captured_place.place;
739 let capture_info = captured_place.info;
740
741 let place_base = if body_owner_is_closure {
742 // Mark the place to be captured by the enclosing closure
743 PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner))
744 } else {
745 // If the body owner isn't a closure then the variable must
746 // be a local variable
747 PlaceBase::Local(*var_hir_id)
748 };
749 let place_with_id = PlaceWithHirId::new(
5869c6ff 750 capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
fc512014
XL
751 place.base_ty,
752 place_base,
753 place.projections.clone(),
754 );
755
756 match capture_info.capture_kind {
757 ty::UpvarCapture::ByValue(_) => {
758 let mode = copy_or_move(&self.mc, &place_with_id);
759 self.delegate.consume(&place_with_id, place_with_id.hir_id, mode);
760 }
761 ty::UpvarCapture::ByRef(upvar_borrow) => {
762 self.delegate.borrow(
763 &place_with_id,
764 place_with_id.hir_id,
765 upvar_borrow.kind,
766 );
767 }
85aaf69f 768 }
1a4d82fc
JJ
769 }
770 }
48663c56 771 }
1a4d82fc 772 }
1a4d82fc
JJ
773}
774
dc9dc135
XL
775fn copy_or_move<'a, 'tcx>(
776 mc: &mc::MemCategorizationContext<'a, 'tcx>,
f035d41b 777 place_with_id: &PlaceWithHirId<'tcx>,
dc9dc135 778) -> ConsumeMode {
f035d41b
XL
779 if !mc.type_is_copy_modulo_regions(
780 place_with_id.place.ty(),
781 mc.tcx().hir().span(place_with_id.hir_id),
782 ) {
783 Move
784 } else {
785 Copy
786 }
1a4d82fc 787}