2
2
//! normal visitor, which just walks the entire body in one shot, the
3
3
//! `ExprUseVisitor` determines how expressions are being used.
4
4
5
+ use hir:: def:: DefKind ;
5
6
// Export these here so that Clippy can use them.
6
7
pub use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , Projection } ;
7
8
@@ -14,7 +15,7 @@ use rustc_index::vec::Idx;
14
15
use rustc_infer:: infer:: InferCtxt ;
15
16
use rustc_middle:: hir:: place:: ProjectionKind ;
16
17
use rustc_middle:: mir:: FakeReadCause ;
17
- use rustc_middle:: ty:: { self , adjustment, TyCtxt } ;
18
+ use rustc_middle:: ty:: { self , adjustment, Ty , TyCtxt } ;
18
19
use rustc_target:: abi:: VariantIdx ;
19
20
use std:: iter;
20
21
@@ -251,28 +252,37 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
251
252
needs_to_be_read = true ;
252
253
}
253
254
}
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.
269
267
needs_to_be_read = true ;
270
268
}
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
+ }
274
274
}
275
275
}
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
+ }
276
286
PatKind :: Lit ( _) | PatKind :: Range ( ..) => {
277
287
// If the PatKind is a Lit or a Range then we want
278
288
// to borrow discr.
@@ -833,3 +843,7 @@ fn delegate_consume<'a, 'tcx>(
833
843
}
834
844
}
835
845
}
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