7
7
8
8
use std:: cell:: { Ref , RefCell } ;
9
9
use std:: ops:: Deref ;
10
- use std:: slice:: from_ref;
11
10
12
- use hir:: Expr ;
13
11
use hir:: def:: DefKind ;
14
12
use hir:: pat_util:: EnumerateAndAdjustIterator as _;
15
13
use rustc_abi:: { FIRST_VARIANT , FieldIdx , VariantIdx } ;
@@ -313,7 +311,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
313
311
314
312
let param_place = self . cat_rvalue ( param. hir_id , param_ty) ;
315
313
316
- self . walk_irrefutable_pat ( & param_place, param. pat ) ?;
314
+ self . fake_read_scrutinee ( & param_place, false ) ?;
315
+ self . walk_pat ( & param_place, param. pat , false ) ?;
317
316
}
318
317
319
318
self . consume_expr ( body. value ) ?;
@@ -455,13 +454,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
455
454
456
455
hir:: ExprKind :: Match ( discr, arms, _) => {
457
456
let discr_place = self . cat_expr ( discr) ?;
458
- self . maybe_read_scrutinee (
459
- discr,
460
- discr_place. clone ( ) ,
461
- arms. iter ( ) . map ( |arm| arm. pat ) ,
462
- ) ?;
457
+ self . fake_read_scrutinee ( & discr_place, true ) ?;
458
+ self . walk_expr ( discr) ?;
463
459
464
- // treatment of the discriminant is handled while walking the arms.
465
460
for arm in arms {
466
461
self . walk_arm ( & discr_place, arm) ?;
467
462
}
@@ -598,116 +593,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
598
593
Ok ( ( ) )
599
594
}
600
595
601
- fn maybe_read_scrutinee < ' t > (
596
+ #[ instrument( skip( self ) , level = "debug" ) ]
597
+ fn fake_read_scrutinee (
602
598
& self ,
603
- discr : & Expr < ' _ > ,
604
- discr_place : PlaceWithHirId < ' tcx > ,
605
- pats : impl Iterator < Item = & ' t hir:: Pat < ' t > > ,
599
+ discr_place : & PlaceWithHirId < ' tcx > ,
600
+ refutable : bool ,
606
601
) -> Result < ( ) , Cx :: Error > {
607
- // Matching should not always be considered a use of the place, hence
608
- // discr does not necessarily need to be borrowed.
609
- // We only want to borrow discr if the pattern contain something other
610
- // than wildcards.
611
- let mut needs_to_be_read = false ;
612
- for pat in pats {
613
- self . cat_pattern ( discr_place. clone ( ) , pat, & mut |place, pat| {
614
- match & pat. kind {
615
- PatKind :: Missing => unreachable ! ( ) ,
616
- PatKind :: Binding ( .., opt_sub_pat) => {
617
- // If the opt_sub_pat is None, then the binding does not count as
618
- // a wildcard for the purpose of borrowing discr.
619
- if opt_sub_pat. is_none ( ) {
620
- needs_to_be_read = true ;
621
- }
622
- }
623
- PatKind :: Never => {
624
- // A never pattern reads the value.
625
- // FIXME(never_patterns): does this do what I expect?
626
- needs_to_be_read = true ;
627
- }
628
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
629
- // A `Path` pattern is just a name like `Foo`. This is either a
630
- // named constant or else it refers to an ADT variant
631
-
632
- let res = self . cx . typeck_results ( ) . qpath_res ( qpath, * hir_id) ;
633
- match res {
634
- Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
635
- // Named constants have to be equated with the value
636
- // being matched, so that's a read of the value being matched.
637
- //
638
- // FIXME: We don't actually reads for ZSTs.
639
- needs_to_be_read = true ;
640
- }
641
- _ => {
642
- // Otherwise, this is a struct/enum variant, and so it's
643
- // only a read if we need to read the discriminant.
644
- needs_to_be_read |=
645
- self . is_multivariant_adt ( place. place . ty ( ) , * span) ;
646
- }
647
- }
648
- }
649
- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
650
- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
651
- // against a multivariant enum or struct. In that case, we have to read
652
- // the discriminant. Otherwise this kind of pattern doesn't actually
653
- // read anything (we'll get invoked for the `...`, which may indeed
654
- // perform some reads).
655
-
656
- let place_ty = place. place . ty ( ) ;
657
- needs_to_be_read |= self . is_multivariant_adt ( place_ty, pat. span ) ;
658
- }
659
- PatKind :: Expr ( _) | PatKind :: Range ( ..) => {
660
- // If the PatKind is a Lit or a Range then we want
661
- // to borrow discr.
662
- needs_to_be_read = true ;
663
- }
664
- PatKind :: Slice ( lhs, wild, rhs) => {
665
- // We don't need to test the length if the pattern is `[..]`
666
- if matches ! ( ( lhs, wild, rhs) , ( & [ ] , Some ( _) , & [ ] ) )
667
- // Arrays have a statically known size, so
668
- // there is no need to read their length
669
- || place. place . ty ( ) . peel_refs ( ) . is_array ( )
670
- {
671
- } else {
672
- needs_to_be_read = true ;
673
- }
674
- }
675
- PatKind :: Or ( _)
676
- | PatKind :: Box ( _)
677
- | PatKind :: Deref ( _)
678
- | PatKind :: Ref ( ..)
679
- | PatKind :: Guard ( ..)
680
- | PatKind :: Wild
681
- | PatKind :: Err ( _) => {
682
- // If the PatKind is Or, Box, or Ref, the decision is made later
683
- // as these patterns contains subpatterns
684
- // If the PatKind is Wild or Err, the decision is made based on the other patterns
685
- // being examined
686
- }
687
- }
688
-
689
- Ok ( ( ) )
690
- } ) ?
691
- }
602
+ let closure_def_id = match discr_place. place . base {
603
+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
604
+ _ => None ,
605
+ } ;
692
606
693
- if needs_to_be_read {
694
- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
607
+ let cause = if refutable {
608
+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
695
609
} else {
696
- let closure_def_id = match discr_place. place . base {
697
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
698
- _ => None ,
699
- } ;
610
+ FakeReadCause :: ForLet ( closure_def_id)
611
+ } ;
700
612
701
- self . delegate . borrow_mut ( ) . fake_read (
702
- & discr_place,
703
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
704
- discr_place. hir_id ,
705
- ) ;
613
+ self . delegate . borrow_mut ( ) . fake_read ( discr_place, cause, discr_place. hir_id ) ;
706
614
707
- // We always want to walk the discriminant. We want to make sure, for instance,
708
- // that the discriminant has been initialized.
709
- self . walk_expr ( discr) ?;
710
- }
711
615
Ok ( ( ) )
712
616
}
713
617
@@ -724,12 +628,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
724
628
self . walk_expr ( expr) ?;
725
629
let expr_place = self . cat_expr ( expr) ?;
726
630
f ( ) ?;
631
+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
632
+ self . walk_pat ( & expr_place, pat, false ) ?;
727
633
if let Some ( els) = els {
728
- // borrowing because we need to test the discriminant
729
- self . maybe_read_scrutinee ( expr, expr_place. clone ( ) , from_ref ( pat) . iter ( ) ) ?;
730
634
self . walk_block ( els) ?;
731
635
}
732
- self . walk_irrefutable_pat ( & expr_place, pat) ?;
733
636
Ok ( ( ) )
734
637
}
735
638
@@ -901,16 +804,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
901
804
discr_place : & PlaceWithHirId < ' tcx > ,
902
805
arm : & hir:: Arm < ' _ > ,
903
806
) -> Result < ( ) , Cx :: Error > {
904
- let closure_def_id = match discr_place. place . base {
905
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
906
- _ => None ,
907
- } ;
908
-
909
- self . delegate . borrow_mut ( ) . fake_read (
910
- discr_place,
911
- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
912
- discr_place. hir_id ,
913
- ) ;
914
807
self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
915
808
916
809
if let Some ( ref e) = arm. guard {
@@ -921,27 +814,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
921
814
Ok ( ( ) )
922
815
}
923
816
924
- /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
925
- /// let binding, and *not* a match arm or nested pat.)
926
- fn walk_irrefutable_pat (
927
- & self ,
928
- discr_place : & PlaceWithHirId < ' tcx > ,
929
- pat : & hir:: Pat < ' _ > ,
930
- ) -> Result < ( ) , Cx :: Error > {
931
- let closure_def_id = match discr_place. place . base {
932
- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
933
- _ => None ,
934
- } ;
935
-
936
- self . delegate . borrow_mut ( ) . fake_read (
937
- discr_place,
938
- FakeReadCause :: ForLet ( closure_def_id) ,
939
- discr_place. hir_id ,
940
- ) ;
941
- self . walk_pat ( discr_place, pat, false ) ?;
942
- Ok ( ( ) )
943
- }
944
-
945
817
/// The core driver for walking a pattern
946
818
///
947
819
/// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1968,6 +1840,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
1968
1840
/// Here, we cannot perform such an accurate checks, because querying
1969
1841
/// whether a type is inhabited requires that it has been fully inferred,
1970
1842
/// which cannot be guaranteed at this point.
1843
+ #[ instrument( skip( self , span) , level = "debug" ) ]
1971
1844
fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1972
1845
if let ty:: Adt ( def, _) = self . cx . structurally_resolve_type ( span, ty) . kind ( ) {
1973
1846
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
0 commit comments