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,116 +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 :: Missing => unreachable ! ( ) ,
615- PatKind :: Binding ( .., opt_sub_pat) => {
616- // If the opt_sub_pat is None, then the binding does not count as
617- // a wildcard for the purpose of borrowing discr.
618- if opt_sub_pat. is_none ( ) {
619- needs_to_be_read = true ;
620- }
621- }
622- PatKind :: Never => {
623- // A never pattern reads the value.
624- // FIXME(never_patterns): does this do what I expect?
625- needs_to_be_read = true ;
626- }
627- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
628- // A `Path` pattern is just a name like `Foo`. This is either a
629- // named constant or else it refers to an ADT variant
630-
631- let res = self . cx . typeck_results ( ) . qpath_res ( qpath, * hir_id) ;
632- match res {
633- Res :: Def ( DefKind :: Const , _) | Res :: Def ( DefKind :: AssocConst , _) => {
634- // Named constants have to be equated with the value
635- // being matched, so that's a read of the value being matched.
636- //
637- // FIXME: We don't actually reads for ZSTs.
638- needs_to_be_read = true ;
639- }
640- _ => {
641- // Otherwise, this is a struct/enum variant, and so it's
642- // only a read if we need to read the discriminant.
643- needs_to_be_read |=
644- self . is_multivariant_adt ( place. place . ty ( ) , * span) ;
645- }
646- }
647- }
648- PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
649- // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
650- // against a multivariant enum or struct. In that case, we have to read
651- // the discriminant. Otherwise this kind of pattern doesn't actually
652- // read anything (we'll get invoked for the `...`, which may indeed
653- // perform some reads).
654-
655- let place_ty = place. place . ty ( ) ;
656- needs_to_be_read |= self . is_multivariant_adt ( place_ty, pat. span ) ;
657- }
658- PatKind :: Expr ( _) | PatKind :: Range ( ..) => {
659- // If the PatKind is a Lit or a Range then we want
660- // to borrow discr.
661- needs_to_be_read = true ;
662- }
663- PatKind :: Slice ( lhs, wild, rhs) => {
664- // We don't need to test the length if the pattern is `[..]`
665- if matches ! ( ( lhs, wild, rhs) , ( & [ ] , Some ( _) , & [ ] ) )
666- // Arrays have a statically known size, so
667- // there is no need to read their length
668- || place. place . ty ( ) . peel_refs ( ) . is_array ( )
669- {
670- } else {
671- needs_to_be_read = true ;
672- }
673- }
674- PatKind :: Or ( _)
675- | PatKind :: Box ( _)
676- | PatKind :: Deref ( _)
677- | PatKind :: Ref ( ..)
678- | PatKind :: Guard ( ..)
679- | PatKind :: Wild
680- | PatKind :: Err ( _) => {
681- // If the PatKind is Or, Box, or Ref, the decision is made later
682- // as these patterns contains subpatterns
683- // If the PatKind is Wild or Err, the decision is made based on the other patterns
684- // being examined
685- }
686- }
687-
688- Ok ( ( ) )
689- } ) ?
690- }
601+ let closure_def_id = match discr_place. place . base {
602+ PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
603+ _ => None ,
604+ } ;
691605
692- if needs_to_be_read {
693- self . borrow_expr ( discr , BorrowKind :: Immutable ) ? ;
606+ let cause = if refutable {
607+ FakeReadCause :: ForMatchedPlace ( closure_def_id )
694608 } else {
695- let closure_def_id = match discr_place. place . base {
696- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
697- _ => None ,
698- } ;
609+ FakeReadCause :: ForLet ( closure_def_id)
610+ } ;
699611
700- self . delegate . borrow_mut ( ) . fake_read (
701- & discr_place,
702- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
703- discr_place. hir_id ,
704- ) ;
612+ self . delegate . borrow_mut ( ) . fake_read ( discr_place, cause, discr_place. hir_id ) ;
705613
706- // We always want to walk the discriminant. We want to make sure, for instance,
707- // that the discriminant has been initialized.
708- self . walk_expr ( discr) ?;
709- }
710614 Ok ( ( ) )
711615 }
712616
@@ -723,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
723627 self . walk_expr ( expr) ?;
724628 let expr_place = self . cat_expr ( expr) ?;
725629 f ( ) ?;
630+ self . fake_read_scrutinee ( & expr_place, els. is_some ( ) ) ?;
631+ self . walk_pat ( & expr_place, pat, false ) ?;
726632 if let Some ( els) = els {
727- // borrowing because we need to test the discriminant
728- self . maybe_read_scrutinee ( expr, expr_place. clone ( ) , from_ref ( pat) . iter ( ) ) ?;
729633 self . walk_block ( els) ?;
730634 }
731- self . walk_irrefutable_pat ( & expr_place, pat) ?;
732635 Ok ( ( ) )
733636 }
734637
@@ -900,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
900803 discr_place : & PlaceWithHirId < ' tcx > ,
901804 arm : & hir:: Arm < ' _ > ,
902805 ) -> Result < ( ) , Cx :: Error > {
903- let closure_def_id = match discr_place. place . base {
904- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
905- _ => None ,
906- } ;
907-
908- self . delegate . borrow_mut ( ) . fake_read (
909- discr_place,
910- FakeReadCause :: ForMatchedPlace ( closure_def_id) ,
911- discr_place. hir_id ,
912- ) ;
913806 self . walk_pat ( discr_place, arm. pat , arm. guard . is_some ( ) ) ?;
914807
915808 if let Some ( ref e) = arm. guard {
@@ -920,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
920813 Ok ( ( ) )
921814 }
922815
923- /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
924- /// let binding, and *not* a match arm or nested pat.)
925- fn walk_irrefutable_pat (
926- & self ,
927- discr_place : & PlaceWithHirId < ' tcx > ,
928- pat : & hir:: Pat < ' _ > ,
929- ) -> Result < ( ) , Cx :: Error > {
930- let closure_def_id = match discr_place. place . base {
931- PlaceBase :: Upvar ( upvar_id) => Some ( upvar_id. closure_expr_id ) ,
932- _ => None ,
933- } ;
934-
935- self . delegate . borrow_mut ( ) . fake_read (
936- discr_place,
937- FakeReadCause :: ForLet ( closure_def_id) ,
938- discr_place. hir_id ,
939- ) ;
940- self . walk_pat ( discr_place, pat, false ) ?;
941- Ok ( ( ) )
942- }
943-
944816 /// The core driver for walking a pattern
945817 ///
946818 /// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1960,8 +1832,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
19601832 /// Here, we cannot perform such an accurate checks, because querying
19611833 /// whether a type is inhabited requires that it has been fully inferred,
19621834 /// which cannot be guaranteed at this point.
1835+ #[ instrument( skip( self , span) , level = "debug" ) ]
19631836 fn is_multivariant_adt ( & self , ty : Ty < ' tcx > , span : Span ) -> bool {
1964- if let ty:: Adt ( def, _) = self . cx . try_structurally_resolve_type ( span, ty) . kind ( ) {
1837+ let ty = self . cx . try_structurally_resolve_type ( span, ty) ;
1838+ debug ! ( ?ty, "is_multivariant_adt: resolved" ) ;
1839+ if let ty:: Adt ( def, _) = ty. kind ( ) {
19651840 // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
19661841 // to assume that more cases will be added to the variant in the future. This mean
19671842 // that we should handle non-exhaustive SingleVariant the same way we would handle
0 commit comments