diff options
| author | bors <bors@rust-lang.org> | 2021-08-28 15:36:38 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-08-28 15:36:38 +0000 |
| commit | 42a2a53ec13b0e6e915acd09a2a9a963e5fa3b92 (patch) | |
| tree | a83f42849691e128fc2c728dad5001ddcfdd74b9 | |
| parent | 84b018341284798fa47f8171f4eb04f18f45cf23 (diff) | |
| parent | c4dba5a64efe340a779d8a1ee8c332140c51180e (diff) | |
| download | rust-42a2a53ec13b0e6e915acd09a2a9a963e5fa3b92.tar.gz rust-42a2a53ec13b0e6e915acd09a2a9a963e5fa3b92.zip | |
Auto merge of #88390 - sexxi-goose:missing-case, r=nikomatsakis
Add missing const edge case We don't "process" const so we need to check for additional cases when the PatKind is a Path. We need to make sure that if there is only one variant that there is no field. If there is one or more field, we will want to borrow the match scrutinee Closes https://github.com/rust-lang/rust/issues/88331 r? `@nikomatsakis`
3 files changed, 93 insertions, 19 deletions
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 024370f8d37..a8be207dbb3 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -2,6 +2,7 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +use hir::def::DefKind; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; @@ -14,7 +15,7 @@ use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, adjustment, TyCtxt}; +use rustc_middle::ty::{self, adjustment, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use std::iter; @@ -251,28 +252,37 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { needs_to_be_read = true; } } - PatKind::TupleStruct(..) - | PatKind::Path(..) - | PatKind::Struct(..) - | PatKind::Tuple(..) => { - // If the PatKind is a TupleStruct, Path, Struct or Tuple then we want to check - // whether the Variant is a MultiVariant or a SingleVariant. We only want - // to borrow discr if it is a MultiVariant. - // If it is a SingleVariant and creates a binding we will handle that when - // this callback gets called again. - - // Get the type of the Place after all projections have been applied - let place_ty = place.place.ty(); - - if let ty::Adt(def, _) = place_ty.kind() { - if def.variants.len() > 1 { + PatKind::Path(qpath) => { + // A `Path` pattern is just a name like `Foo`. This is either a + // named constant or else it refers to an ADT variant + + let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); + match res { + Res::Def(DefKind::Const, _) + | Res::Def(DefKind::AssocConst, _) => { + // Named constants have to be equated with the value + // being matched, so that's a read of the value being matched. + // + // FIXME: We don't actually reads for ZSTs. needs_to_be_read = true; } - } else { - // If it is not ty::Adt, then it should be read - needs_to_be_read = true; + _ => { + // Otherwise, this is a struct/enum variant, and so it's + // only a read if we need to read the discriminant. + needs_to_be_read |= is_multivariant_adt(place.place.ty()); + } } } + PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => { + // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching + // against a multivariant enum or struct. In that case, we have to read + // the discriminant. Otherwise this kind of pattern doesn't actually + // read anything (we'll get invoked for the `...`, which may indeed + // perform some reads). + + let place_ty = place.place.ty(); + needs_to_be_read |= is_multivariant_adt(place_ty); + } PatKind::Lit(_) | PatKind::Range(..) => { // If the PatKind is a Lit or a Range then we want // to borrow discr. @@ -833,3 +843,7 @@ fn delegate_consume<'a, 'tcx>( } } } + +fn is_multivariant_adt(ty: Ty<'tcx>) -> bool { + if let ty::Adt(def, _) = ty.kind() { def.variants.len() > 1 } else { false } +} diff --git a/src/test/ui/closures/2229_closure_analysis/issue-88331.rs b/src/test/ui/closures/2229_closure_analysis/issue-88331.rs new file mode 100644 index 00000000000..0a6d71c68ae --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-88331.rs @@ -0,0 +1,33 @@ +// edition:2021 + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Opcode(pub u8); + +impl Opcode { + pub const OP1: Opcode = Opcode(0x1); +} + +pub fn example1(msg_type: Opcode) -> impl FnMut(&[u8]) { + move |i| match msg_type { + //~^ ERROR: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered + Opcode::OP1 => unimplemented!(), + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Opcode2(Opcode); + +impl Opcode2 { + pub const OP2: Opcode2 = Opcode2(Opcode(0x1)); +} + + +pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) { + + move |i| match msg_type { + //~^ ERROR: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered + Opcode2::OP2=> unimplemented!(), + } +} + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/issue-88331.stderr b/src/test/ui/closures/2229_closure_analysis/issue-88331.stderr new file mode 100644 index 00000000000..f02d23464f1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-88331.stderr @@ -0,0 +1,27 @@ +error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered + --> $DIR/issue-88331.rs:11:20 + | +LL | pub struct Opcode(pub u8); + | -------------------------- `Opcode` defined here +... +LL | move |i| match msg_type { + | ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Opcode` + +error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered + --> $DIR/issue-88331.rs:27:20 + | +LL | pub struct Opcode2(Opcode); + | --------------------------- `Opcode2` defined here +... +LL | move |i| match msg_type { + | ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `Opcode2` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. |
