@@ -941,6 +941,19 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
941941    } 
942942
943943    /// The core driver for walking a pattern 
944+      /// 
945+      /// This should mirror how pattern-matching gets lowered to MIR, as 
946+      /// otherwise lowering will ICE when trying to resolve the upvars. 
947+      /// 
948+      /// However, it is okay to approximate it here by doing *more* accesses than 
949+      /// the actual MIR builder will, which is useful when some checks are too 
950+      /// cumbersome to perform here. For example, if after typeck it becomes 
951+      /// clear that only one variant of an enum is inhabited, and therefore a 
952+      /// read of the discriminant is not necessary, `walk_pat` will have 
953+      /// over-approximated the necessary upvar capture granularity. 
954+      /// 
955+      /// Do note that discrepancies like these do still create obscure corners 
956+      /// in the semantics of the language, and should be avoided if possible. 
944957     #[ instrument( skip( self ) ,  level = "debug" ) ]  
945958    fn  walk_pat ( 
946959        & self , 
@@ -950,6 +963,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
950963    )  -> Result < ( ) ,  Cx :: Error >  { 
951964        let  tcx = self . cx . tcx ( ) ; 
952965        self . cat_pattern ( discr_place. clone ( ) ,  pat,  & mut  |place,  pat| { 
966+             debug ! ( "walk_pat: pat.kind={:?}" ,  pat. kind) ; 
967+             let  read_discriminant = || { 
968+                 self . delegate . borrow_mut ( ) . borrow ( place,  discr_place. hir_id ,  BorrowKind :: Immutable ) ; 
969+             } ; 
970+ 
953971            match  pat. kind  { 
954972                PatKind :: Binding ( _,  canonical_id,  ..)  => { 
955973                    debug ! ( "walk_pat: binding place={:?} pat={:?}" ,  place,  pat) ; 
@@ -972,11 +990,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
972990                    // binding when lowering pattern guards to ensure that the guard does not 
973991                    // modify the scrutinee. 
974992                    if  has_guard { 
975-                         self . delegate . borrow_mut ( ) . borrow ( 
976-                             place, 
977-                             discr_place. hir_id , 
978-                             BorrowKind :: Immutable , 
979-                         ) ; 
993+                         read_discriminant ( ) ; 
980994                    } 
981995
982996                    // It is also a borrow or copy/move of the value being matched. 
@@ -1008,13 +1022,70 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
10081022                PatKind :: Never  => { 
10091023                    // A `!` pattern always counts as an immutable read of the discriminant, 
10101024                    // even in an irrefutable pattern. 
1011-                     self . delegate . borrow_mut ( ) . borrow ( 
1012-                         place, 
1013-                         discr_place. hir_id , 
1014-                         BorrowKind :: Immutable , 
1015-                     ) ; 
1025+                     read_discriminant ( ) ; 
1026+                 } 
1027+                 PatKind :: Expr ( PatExpr  {  kind :  PatExprKind :: Path ( qpath) ,  hir_id,  span } )  => { 
1028+                     // A `Path` pattern is just a name like `Foo`. This is either a 
1029+                     // named constant or else it refers to an ADT variant 
1030+ 
1031+                     let  res = self . cx . typeck_results ( ) . qpath_res ( qpath,  * hir_id) ; 
1032+                     match  res { 
1033+                         Res :: Def ( DefKind :: Const ,  _)  | Res :: Def ( DefKind :: AssocConst ,  _)  => { 
1034+                             // Named constants have to be equated with the value 
1035+                             // being matched, so that's a read of the value being matched. 
1036+                             // 
1037+                             // FIXME: Does the MIR code skip this read when matching on a ZST? 
1038+                             // If so, we can also skip it here. 
1039+                             read_discriminant ( ) ; 
1040+                         } 
1041+                         _ => { 
1042+                             // Otherwise, this is a struct/enum variant, and so it's 
1043+                             // only a read if we need to read the discriminant. 
1044+                             if  self . is_multivariant_adt ( place. place . ty ( ) ,  * span)  { 
1045+                                 read_discriminant ( ) ; 
1046+                             } 
1047+                         } 
1048+                     } 
1049+                 } 
1050+                 PatKind :: Expr ( _)  | PatKind :: Range ( ..)  => { 
1051+                     // When matching against a literal or range, we need to 
1052+                     // borrow the place to compare it against the pattern. 
1053+                     // 
1054+                     // FIXME: What if the type being matched only has one 
1055+                     // possible value? 
1056+                     // FIXME: What if the range is the full range of the type 
1057+                     // and doesn't actually require a discriminant read? 
1058+                     read_discriminant ( ) ; 
1059+                 } 
1060+                 PatKind :: Struct ( ..)  | PatKind :: TupleStruct ( ..)  => { 
1061+                     if  self . is_multivariant_adt ( place. place . ty ( ) ,  pat. span )  { 
1062+                         read_discriminant ( ) ; 
1063+                     } 
1064+                 } 
1065+                 PatKind :: Slice ( lhs,  wild,  rhs)  => { 
1066+                     // We don't need to test the length if the pattern is `[..]` 
1067+                     if  matches ! ( ( lhs,  wild,  rhs) ,  ( & [ ] ,  Some ( _) ,  & [ ] ) ) 
1068+                         // Arrays have a statically known size, so 
1069+                         // there is no need to read their length 
1070+                         || place. place . ty ( ) . peel_refs ( ) . is_array ( ) 
1071+                     { 
1072+                         // No read necessary 
1073+                     }  else  { 
1074+                         read_discriminant ( ) ; 
1075+                     } 
1076+                 } 
1077+                 PatKind :: Or ( _) 
1078+                 | PatKind :: Box ( _) 
1079+                 | PatKind :: Ref ( ..) 
1080+                 | PatKind :: Guard ( ..) 
1081+                 | PatKind :: Tuple ( ..) 
1082+                 | PatKind :: Wild 
1083+                 | PatKind :: Err ( _)  => { 
1084+                     // If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses 
1085+                     // are made later as these patterns contains subpatterns. 
1086+                     // If the PatKind is Wild or Err, they are made when processing the other patterns 
1087+                     // being examined 
10161088                } 
1017-                 _ => { } 
10181089            } 
10191090
10201091            Ok ( ( ) ) 
@@ -1849,6 +1920,14 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
18491920        Ok ( ( ) ) 
18501921    } 
18511922
1923+     /// Checks whether a type has multiple variants, and therefore, whether a 
1924+      /// read of the discriminant might be necessary. Note that the actual MIR 
1925+      /// builder code does a more specific check, filtering out variants that 
1926+      /// happen to be uninhabited. 
1927+      /// 
1928+      /// Here, we cannot perform such an accurate checks, because querying 
1929+      /// whether a type is inhabited requires that it has been fully inferred, 
1930+      /// which cannot be guaranteed at this point. 
18521931     fn  is_multivariant_adt ( & self ,  ty :  Ty < ' tcx > ,  span :  Span )  -> bool  { 
18531932        if  let  ty:: Adt ( def,  _)  = self . cx . try_structurally_resolve_type ( span,  ty) . kind ( )  { 
18541933            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need 
0 commit comments