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 } ;
@@ -312,7 +310,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
312310
313311 let param_place = self . cat_rvalue ( param. hir_id , param_ty) ;
314312
315- self . walk_irrefutable_pat ( & param_place, param. pat ) ?;
313+ self . fake_read_scrutinee ( & param_place, false ) ?;
314+ self . walk_pat ( & param_place, param. pat , false ) ?;
316315 }
317316
318317 self . consume_expr ( body. value ) ?;
@@ -454,13 +453,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
454453
455454 hir:: ExprKind :: Match ( discr, arms, _) => {
456455 let discr_place = self . cat_expr ( discr) ?;
457- self . maybe_read_scrutinee (
458- discr,
459- discr_place. clone ( ) ,
460- arms. iter ( ) . map ( |arm| arm. pat ) ,
461- ) ?;
456+ self . fake_read_scrutinee ( & discr_place, true ) ?;
457+ self . walk_expr ( discr) ?;
462458
463- // treatment of the discriminant is handled while walking the arms.
464459 for arm in arms {
465460 self . walk_arm ( & discr_place, arm) ?;
466461 }
@@ -597,115 +592,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
597592 Ok ( ( ) )
598593 }
599594
600- fn maybe_read_scrutinee < ' t > (
595+ #[ instrument( skip( self ) , level = "debug" ) ]
596+ fn fake_read_scrutinee (
601597 & self ,
602- discr : & Expr < ' _ > ,
603- discr_place : PlaceWithHirId < ' tcx > ,
604- pats : impl Iterator < Item = & ' t hir:: Pat < ' t > > ,
598+ discr_place : & PlaceWithHirId < ' tcx > ,
599+ refutable : bool ,
605600 ) -> Result < ( ) , Cx :: Error > {
606- // Matching should not always be considered a use of the place, hence
607- // discr does not necessarily need to be borrowed.
608- // We only want to borrow discr if the pattern contain something other
609- // than wildcards.
610- let mut needs_to_be_read = false ;
611- for pat in pats {
612- self . cat_pattern ( discr_place. clone ( ) , pat, & mut |place, pat| {
613- match & pat. kind {
614- PatKind :: Binding ( .., opt_sub_pat) => {
615- // If the opt_sub_pat is None, then the binding does not count as
616- // a wildcard for the purpose of borrowing discr.
617- if opt_sub_pat. is_none ( ) {
618- needs_to_be_read = true ;
619- }
620- }
621- PatKind :: Never => {
622- // A never pattern reads the value.
623- // FIXME(never_patterns): does this do what I expect?
624- needs_to_be_read = true ;
625- }
626- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
627- // A `Path` pattern is just a name like `Foo`. This is either a
628- // named constant or else it refers to an ADT variant
629-
630- let res = self . cx . typeck_results ( ) . qpath_res ( qpath, * hir_id) ;
631- match res {
632- Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
633- // Named constants have to be equated with the value
634- // being matched, so that's a read of the value being matched.
635- //
636- // FIXME: We don't actually reads for ZSTs.
637- needs_to_be_read = true ;
638- }
639- _ => {
640- // Otherwise, this is a struct/enum variant, and so it's
641- // only a read if we need to read the discriminant.
642- needs_to_be_read |=
643- self . is_multivariant_adt ( place. place . ty ( ) , * span) ;
644- }
645- }
646- }
647- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
648- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
649- // against a multivariant enum or struct. In that case, we have to read
650- // the discriminant. Otherwise this kind of pattern doesn't actually
651- // read anything (we'll get invoked for the `...`, which may indeed
652- // perform some reads).
653-
654- let place_ty = place. place . ty ( ) ;
655- needs_to_be_read |= self . is_multivariant_adt ( place_ty, pat. span ) ;
656- }
657- PatKind :: Expr ( _) | PatKind :: Range ( ..) => {
658- // If the PatKind is a Lit or a Range then we want
659- // to borrow discr.
660- needs_to_be_read = true ;
661- }
662- PatKind :: Slice ( lhs, wild, rhs) => {
663- // We don't need to test the length if the pattern is `[..]`
664- if matches ! ( ( lhs, wild, rhs) , ( & [ ] , Some ( _) , & [ ] ) )
665- // Arrays have a statically known size, so
666- // there is no need to read their length
667- || place. place . ty ( ) . peel_refs ( ) . is_array ( )
668- {
669- } else {
670- needs_to_be_read = true ;
671- }
672- }
673- PatKind :: Or ( _)
674- | PatKind :: Box ( _)
675- | PatKind :: Deref ( _)
676- | PatKind :: Ref ( ..)
677- | PatKind :: Guard ( ..)
678- | PatKind :: Wild
679- | PatKind :: Err ( _) => {
680- // If the PatKind is Or, Box, or Ref, the decision is made later
681- // as these patterns contains subpatterns
682- // If the PatKind is Wild or Err, the decision is made based on the other patterns
683- // being examined
684- }
685- }
686-
687- Ok ( ( ) )
688- } ) ?
689- }
601+ let closure_def_id = match discr_place. place . base {
602+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
603+ _ => None ,
604+ } ;
690605
691- if needs_to_be_read {
692- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
606+ let cause = if refutable {
607+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
693608 } else {
694- let closure_def_id = match discr_place. place . base {
695- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
696- _ => None ,
697- } ;
609+ FakeReadCause :: ForLet ( closure_def_id)
610+ } ;
698611
699- self . delegate . borrow_mut ( ) . fake_read (
700- & discr_place,
701- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
702- discr_place. hir_id ,
703- ) ;
612+ self . delegate . borrow_mut ( ) . fake_read ( discr_place, cause, discr_place. hir_id ) ;
704613
705- // We always want to walk the discriminant. We want to make sure, for instance,
706- // that the discriminant has been initialized.
707- self . walk_expr ( discr) ?;
708- }
709614 Ok ( ( ) )
710615 }
711616
@@ -722,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
722627 self . walk_expr ( expr) ?;
723628 let expr_place = self . cat_expr ( expr) ?;
724629 f ( ) ?;
630+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
631+ self . walk_pat ( & expr_place, pat, false ) ?;
725632 if let Some ( els) = els {
726- // borrowing because we need to test the discriminant
727- self . maybe_read_scrutinee ( expr, expr_place. clone ( ) , from_ref ( pat) . iter ( ) ) ?;
728633 self . walk_block ( els) ?;
729634 }
730- self . walk_irrefutable_pat ( & expr_place, pat) ?;
731635 Ok ( ( ) )
732636 }
733637
@@ -899,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
899803 discr_place : & PlaceWithHirId < ' tcx > ,
900804 arm : & hir:: Arm < ' _ > ,
901805 ) -> Result < ( ) , Cx :: Error > {
902- let closure_def_id = match discr_place. place . base {
903- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
904- _ => None ,
905- } ;
906-
907- self . delegate . borrow_mut ( ) . fake_read (
908- discr_place,
909- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
910- discr_place. hir_id ,
911- ) ;
912806 self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
913807
914808 if let Some ( ref e) = arm. guard {
@@ -919,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
919813 Ok ( ( ) )
920814 }
921815
922- /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
923- /// let binding, and *not* a match arm or nested pat.)
924- fn walk_irrefutable_pat (
925- & self ,
926- discr_place : & PlaceWithHirId < ' tcx > ,
927- pat : & hir:: Pat < ' _ > ,
928- ) -> Result < ( ) , Cx :: Error > {
929- let closure_def_id = match discr_place. place . base {
930- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
931- _ => None ,
932- } ;
933-
934- self . delegate . borrow_mut ( ) . fake_read (
935- discr_place,
936- FakeReadCause :: ForLet ( closure_def_id) ,
937- discr_place. hir_id ,
938- ) ;
939- self . walk_pat ( discr_place, pat, false ) ?;
940- Ok ( ( ) )
941- }
942-
943816 /// The core driver for walking a pattern
944817 ///
945818 /// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1928,8 +1801,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
19281801 /// Here, we cannot perform such an accurate checks, because querying
19291802 /// whether a type is inhabited requires that it has been fully inferred,
19301803 /// which cannot be guaranteed at this point.
1804+ #[ instrument( skip( self , span) , level = "debug" ) ]
19311805 fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1932- if let ty:: Adt ( def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1806+ let ty = self . cx . try_structurally_resolve_type ( span, ty) ;
1807+ debug ! ( ?ty, "is_multivariant_adt: resolved" ) ;
1808+ if let ty:: Adt ( def, _) = ty. kind ( ) {
19331809 // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
19341810 // to assume that more cases will be added to the variant in the future. This mean
19351811 // that we should handle non-exhaustive SingleVariant the same way we would handle
0 commit comments