77
88use std:: cell:: { Ref , RefCell } ;
99use std:: ops:: Deref ;
10- use std:: slice:: from_ref;
1110
12- use hir:: Expr ;
1311use hir:: def:: DefKind ;
1412use hir:: pat_util:: EnumerateAndAdjustIterator as _;
1513use rustc_abi:: { FIRST_VARIANT , FieldIdx , VariantIdx } ;
@@ -313,7 +311,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
313311
314312 let param_place = self . cat_rvalue ( param. hir_id , param_ty) ;
315313
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 ) ?;
317316 }
318317
319318 self . consume_expr ( body. value ) ?;
@@ -455,13 +454,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
455454
456455 hir:: ExprKind :: Match ( discr, arms, _) => {
457456 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) ?;
463459
464- // treatment of the discriminant is handled while walking the arms.
465460 for arm in arms {
466461 self . walk_arm ( & discr_place, arm) ?;
467462 }
@@ -598,116 +593,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
598593 Ok ( ( ) )
599594 }
600595
601- fn maybe_read_scrutinee < ' t > (
596+ #[ instrument( skip( self ) , level = "debug" ) ]
597+ fn fake_read_scrutinee (
602598 & 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 ,
606601 ) -> 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+ } ;
692606
693- if needs_to_be_read {
694- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
607+ let cause = if refutable {
608+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
695609 } 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+ } ;
700612
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 ) ;
706614
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- }
711615 Ok ( ( ) )
712616 }
713617
@@ -724,12 +628,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
724628 self . walk_expr ( expr) ?;
725629 let expr_place = self . cat_expr ( expr) ?;
726630 f ( ) ?;
631+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
632+ self . walk_pat ( & expr_place, pat, false ) ?;
727633 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 ( ) ) ?;
730634 self . walk_block ( els) ?;
731635 }
732- self . walk_irrefutable_pat ( & expr_place, pat) ?;
733636 Ok ( ( ) )
734637 }
735638
@@ -901,16 +804,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
901804 discr_place : & PlaceWithHirId < ' tcx > ,
902805 arm : & hir:: Arm < ' _ > ,
903806 ) -> 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- ) ;
914807 self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
915808
916809 if let Some ( ref e) = arm. guard {
@@ -921,27 +814,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
921814 Ok ( ( ) )
922815 }
923816
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-
945817 /// The core driver for walking a pattern
946818 ///
947819 /// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1988,6 +1860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
19881860 /// Here, we cannot perform such an accurate checks, because querying
19891861 /// whether a type is inhabited requires that it has been fully inferred,
19901862 /// which cannot be guaranteed at this point.
1863+ #[ instrument( skip( self , span) , level = "debug" ) ]
19911864 fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
19921865 if let ty:: Adt ( def, _) = self . cx . structurally_resolve_type ( span, ty) . kind ( ) {
19931866 // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
0 commit comments