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,43 +252,34 @@ 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.
269265 needs_to_be_read = true ;
270- } else if let Some ( variant) = def. variants. iter( ) . next( ) {
271- // We need to handle `const` in match arms slightly differently
272- // as they are not processed the same way as other match arms.
273- // Consider this const `const OP1: Opcode = Opcode(0x1)`, this
274- // will generate a pattern with kind Path while if use Opcode(0x1)
275- // this will generate pattern TupleStruct and Lit.
276- // When dealing with pat kind Path we need to make additional checks
277- // to ensure we have all the info needed to make a decision on whether
278- // to borrow discr.
279- //
280- // If the pat kind is a Path we want to check whether the
281- // variant contains at least one field. If that's the case,
282- // we want to borrow discr.
283- if matches!( pat. kind, PatKind :: Path ( ..) )
284- && variant. fields. len( ) > 0
285- {
286- needs_to_be_read = true ;
287- }
288266 }
289- } else {
290- // If it is not ty::Adt, then it should be read
267+ _ => {
268+ // Otherwise, this is a struct/enum variant, and so it's
269+ // only a read if we need to read the discriminant.
270+ needs_to_be_read = is_multivariant_adt( place. place. ty( ) ) ;
271+ }
272+ }
273+ }
274+ PatKind :: TupleStruct ( ..) | PatKind :: Struct ( ..) | PatKind :: Tuple ( ..) => {
275+ // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
276+ // against a multivariant enum or struct. In that case, we have to read
277+ // the discriminant. Otherwise this kind of pattern doesn't actually
278+ // read anything (we'll get invoked for the `...`, which may indeed
279+ // perform some reads).
280+
281+ let place_ty = place. place. ty( ) ;
282+ if is_multivariant_adt( place_ty) {
291283 needs_to_be_read = true ;
292284 }
293285 }
@@ -854,3 +846,7 @@ fn delegate_consume<'a, 'tcx>(
854846 }
855847 }
856848}
849+
850+ fn is_multivariant_adt ( ty : Ty < ' tcx > ) -> bool {
851+ if let ty:: Adt ( def, _) = ty. kind ( ) { def. variants . len ( ) > 1 } else { false }
852+ }
0 commit comments