2
2
//! normal visitor, which just walks the entire body in one shot, the
3
3
//! `ExprUseVisitor` determines how expressions are being used.
4
4
5
+ use std:: slice:: from_ref;
6
+
5
7
use hir:: def:: DefKind ;
8
+ use hir:: Expr ;
6
9
// Export these here so that Clippy can use them.
7
10
pub use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , Projection } ;
8
11
@@ -257,91 +260,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
257
260
258
261
hir:: ExprKind :: Match ( ref discr, arms, _) => {
259
262
let discr_place = return_if_err ! ( self . mc. cat_expr( discr) ) ;
260
-
261
- // Matching should not always be considered a use of the place, hence
262
- // discr does not necessarily need to be borrowed.
263
- // We only want to borrow discr if the pattern contain something other
264
- // than wildcards.
265
- let ExprUseVisitor { ref mc, body_owner : _, delegate : _ } = * self ;
266
- let mut needs_to_be_read = false ;
267
- for arm in arms. iter ( ) {
268
- return_if_err ! ( mc. cat_pattern( discr_place. clone( ) , arm. pat, |place, pat| {
269
- match & pat. kind {
270
- PatKind :: Binding ( .., opt_sub_pat) => {
271
- // If the opt_sub_pat is None, than the binding does not count as
272
- // a wildcard for the purpose of borrowing discr.
273
- if opt_sub_pat. is_none( ) {
274
- needs_to_be_read = true ;
275
- }
276
- }
277
- PatKind :: Path ( qpath) => {
278
- // A `Path` pattern is just a name like `Foo`. This is either a
279
- // named constant or else it refers to an ADT variant
280
-
281
- let res = self . mc. typeck_results. qpath_res( qpath, pat. hir_id) ;
282
- match res {
283
- Res :: Def ( DefKind :: Const , _)
284
- | Res :: Def ( DefKind :: AssocConst , _) => {
285
- // Named constants have to be equated with the value
286
- // being matched, so that's a read of the value being matched.
287
- //
288
- // FIXME: We don't actually reads for ZSTs.
289
- needs_to_be_read = true ;
290
- }
291
- _ => {
292
- // Otherwise, this is a struct/enum variant, and so it's
293
- // only a read if we need to read the discriminant.
294
- needs_to_be_read |= is_multivariant_adt( place. place. ty( ) ) ;
295
- }
296
- }
297
- }
298
- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
299
- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
300
- // against a multivariant enum or struct. In that case, we have to read
301
- // the discriminant. Otherwise this kind of pattern doesn't actually
302
- // read anything (we'll get invoked for the `...`, which may indeed
303
- // perform some reads).
304
-
305
- let place_ty = place. place. ty( ) ;
306
- needs_to_be_read |= is_multivariant_adt( place_ty) ;
307
- }
308
- PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
309
- // If the PatKind is a Lit or a Range then we want
310
- // to borrow discr.
311
- needs_to_be_read = true ;
312
- }
313
- PatKind :: Or ( _)
314
- | PatKind :: Box ( _)
315
- | PatKind :: Slice ( ..)
316
- | PatKind :: Ref ( ..)
317
- | PatKind :: Wild => {
318
- // If the PatKind is Or, Box, Slice or Ref, the decision is made later
319
- // as these patterns contains subpatterns
320
- // If the PatKind is Wild, the decision is made based on the other patterns being
321
- // examined
322
- }
323
- }
324
- } ) ) ;
325
- }
326
-
327
- if needs_to_be_read {
328
- self . borrow_expr ( discr, ty:: ImmBorrow ) ;
329
- } else {
330
- let closure_def_id = match discr_place. place . base {
331
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id . to_def_id ( ) ) ,
332
- _ => None ,
333
- } ;
334
-
335
- self . delegate . fake_read (
336
- & discr_place,
337
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
338
- discr_place. hir_id ,
339
- ) ;
340
-
341
- // We always want to walk the discriminant. We want to make sure, for instance,
342
- // that the discriminant has been initialized.
343
- self . walk_expr ( discr) ;
344
- }
263
+ self . maybe_read_scrutinee (
264
+ discr,
265
+ discr_place. clone ( ) ,
266
+ arms. iter ( ) . map ( |arm| arm. pat ) ,
267
+ ) ;
345
268
346
269
// treatment of the discriminant is handled while walking the arms.
347
270
for arm in arms {
@@ -470,6 +393,97 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
470
393
}
471
394
}
472
395
396
+ fn maybe_read_scrutinee < ' t > (
397
+ & mut self ,
398
+ discr : & Expr < ' _ > ,
399
+ discr_place : PlaceWithHirId < ' tcx > ,
400
+ pats : impl Iterator < Item = & ' t hir:: Pat < ' t > > ,
401
+ ) {
402
+ // Matching should not always be considered a use of the place, hence
403
+ // discr does not necessarily need to be borrowed.
404
+ // We only want to borrow discr if the pattern contain something other
405
+ // than wildcards.
406
+ let ExprUseVisitor { ref mc, body_owner : _, delegate : _ } = * self ;
407
+ let mut needs_to_be_read = false ;
408
+ for pat in pats {
409
+ return_if_err ! ( mc. cat_pattern( discr_place. clone( ) , pat, |place, pat| {
410
+ match & pat. kind {
411
+ PatKind :: Binding ( .., opt_sub_pat) => {
412
+ // If the opt_sub_pat is None, than the binding does not count as
413
+ // a wildcard for the purpose of borrowing discr.
414
+ if opt_sub_pat. is_none( ) {
415
+ needs_to_be_read = true ;
416
+ }
417
+ }
418
+ PatKind :: Path ( qpath) => {
419
+ // A `Path` pattern is just a name like `Foo`. This is either a
420
+ // named constant or else it refers to an ADT variant
421
+
422
+ let res = self . mc. typeck_results. qpath_res( qpath, pat. hir_id) ;
423
+ match res {
424
+ Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
425
+ // Named constants have to be equated with the value
426
+ // being matched, so that's a read of the value being matched.
427
+ //
428
+ // FIXME: We don't actually reads for ZSTs.
429
+ needs_to_be_read = true ;
430
+ }
431
+ _ => {
432
+ // Otherwise, this is a struct/enum variant, and so it's
433
+ // only a read if we need to read the discriminant.
434
+ needs_to_be_read |= is_multivariant_adt( place. place. ty( ) ) ;
435
+ }
436
+ }
437
+ }
438
+ PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
439
+ // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
440
+ // against a multivariant enum or struct. In that case, we have to read
441
+ // the discriminant. Otherwise this kind of pattern doesn't actually
442
+ // read anything (we'll get invoked for the `...`, which may indeed
443
+ // perform some reads).
444
+
445
+ let place_ty = place. place. ty( ) ;
446
+ needs_to_be_read |= is_multivariant_adt( place_ty) ;
447
+ }
448
+ PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
449
+ // If the PatKind is a Lit or a Range then we want
450
+ // to borrow discr.
451
+ needs_to_be_read = true ;
452
+ }
453
+ PatKind :: Or ( _)
454
+ | PatKind :: Box ( _)
455
+ | PatKind :: Slice ( ..)
456
+ | PatKind :: Ref ( ..)
457
+ | PatKind :: Wild => {
458
+ // If the PatKind is Or, Box, Slice or Ref, the decision is made later
459
+ // as these patterns contains subpatterns
460
+ // If the PatKind is Wild, the decision is made based on the other patterns being
461
+ // examined
462
+ }
463
+ }
464
+ } ) ) ;
465
+ }
466
+
467
+ if needs_to_be_read {
468
+ self . borrow_expr ( discr, ty:: ImmBorrow ) ;
469
+ } else {
470
+ let closure_def_id = match discr_place. place . base {
471
+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id . to_def_id ( ) ) ,
472
+ _ => None ,
473
+ } ;
474
+
475
+ self . delegate . fake_read (
476
+ & discr_place,
477
+ FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
478
+ discr_place. hir_id ,
479
+ ) ;
480
+
481
+ // We always want to walk the discriminant. We want to make sure, for instance,
482
+ // that the discriminant has been initialized.
483
+ self . walk_expr ( discr) ;
484
+ }
485
+ }
486
+
473
487
fn walk_local < F > (
474
488
& mut self ,
475
489
expr : & hir:: Expr < ' _ > ,
@@ -484,10 +498,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
484
498
f ( self ) ;
485
499
if let Some ( els) = els {
486
500
// borrowing because we need to test the descriminant
487
- self . borrow_expr ( expr, ImmBorrow ) ;
501
+ // self.borrow_expr(expr, ImmBorrow);
502
+ self . maybe_read_scrutinee ( expr, expr_place, from_ref ( pat) . iter ( ) ) ;
488
503
self . walk_block ( els)
504
+ } else {
505
+ self . walk_irrefutable_pat ( & expr_place, & pat) ;
489
506
}
490
- self . walk_irrefutable_pat ( & expr_place, & pat) ;
491
507
}
492
508
493
509
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
0 commit comments