22//! normal visitor, which just walks the entire body in one shot, the
33//! `ExprUseVisitor` determines how expressions are being used.
44
5+ use hir:: def:: DefKind ;
56// Export these here so that Clippy can use them.
67pub use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , Projection } ;
78
@@ -14,7 +15,7 @@ use rustc_index::vec::Idx;
1415use rustc_infer:: infer:: InferCtxt ;
1516use rustc_middle:: hir:: place:: ProjectionKind ;
1617use rustc_middle:: mir:: FakeReadCause ;
17- use rustc_middle:: ty:: { self , adjustment, TyCtxt } ;
18+ use rustc_middle:: ty:: { self , adjustment, Ty , TyCtxt } ;
1819use rustc_target:: abi:: VariantIdx ;
1920use std:: iter;
2021
@@ -251,28 +252,37 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
251252 needs_to_be_read = true ;
252253 }
253254 }
254- PatKind :: TupleStruct ( ..)
255- | PatKind :: Path ( ..)
256- | PatKind :: Struct ( ..)
257- | PatKind :: Tuple ( ..) => {
258- // If the PatKind is a TupleStruct, Path, Struct or Tuple then we want to check
259- // whether the Variant is a MultiVariant or a SingleVariant. We only want
260- // to borrow discr if it is a MultiVariant.
261- // If it is a SingleVariant and creates a binding we will handle that when
262- // this callback gets called again.
263-
264- // Get the type of the Place after all projections have been applied
265- let place_ty = place. place. ty( ) ;
266-
267- if let ty:: Adt ( def, _) = place_ty. kind( ) {
268- if def. variants. len( ) > 1 {
255+ PatKind :: Path ( qpath) => {
256+ // A `Path` pattern is just a name like `Foo`. This is either a
257+ // named constant or else it refers to an ADT variant
258+
259+ let res = self . mc. typeck_results. qpath_res( qpath, pat. hir_id) ;
260+ match res {
261+ Res :: Def ( DefKind :: Const , _)
262+ | Res :: Def ( DefKind :: AssocConst , _) => {
263+ // Named constants have to be equated with the value
264+ // being matched, so that's a read of the value being matched.
265+ //
266+ // FIXME: We don't actually reads for ZSTs.
269267 needs_to_be_read = true ;
270268 }
271- } else {
272- // If it is not ty::Adt, then it should be read
273- needs_to_be_read = true ;
269+ _ => {
270+ // Otherwise, this is a struct/enum variant, and so it's
271+ // only a read if we need to read the discriminant.
272+ needs_to_be_read |= is_multivariant_adt( place. place. ty( ) ) ;
273+ }
274274 }
275275 }
276+ PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
277+ // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
278+ // against a multivariant enum or struct. In that case, we have to read
279+ // the discriminant. Otherwise this kind of pattern doesn't actually
280+ // read anything (we'll get invoked for the `...`, which may indeed
281+ // perform some reads).
282+
283+ let place_ty = place. place. ty( ) ;
284+ needs_to_be_read |= is_multivariant_adt( place_ty) ;
285+ }
276286 PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
277287 // If the PatKind is a Lit or a Range then we want
278288 // to borrow discr.
@@ -833,3 +843,7 @@ fn delegate_consume<'a, 'tcx>(
833843 }
834844 }
835845}
846+
847+ fn is_multivariant_adt ( ty : Ty < ' tcx > ) -> bool {
848+ if let ty:: Adt ( def, _) = ty. kind ( ) { def. variants . len ( ) > 1 } else { false }
849+ }
0 commit comments