Skip to content

Commit 42a2a53

Browse files
committed
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 #88331 r? `@nikomatsakis`
2 parents 84b0183 + c4dba5a commit 42a2a53

File tree

3 files changed

+93
-19
lines changed

3 files changed

+93
-19
lines changed

compiler/rustc_typeck/src/expr_use_visitor.rs

+33-19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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.
67
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
78

@@ -14,7 +15,7 @@ use rustc_index::vec::Idx;
1415
use rustc_infer::infer::InferCtxt;
1516
use rustc_middle::hir::place::ProjectionKind;
1617
use rustc_middle::mir::FakeReadCause;
17-
use rustc_middle::ty::{self, adjustment, TyCtxt};
18+
use rustc_middle::ty::{self, adjustment, Ty, TyCtxt};
1819
use rustc_target::abi::VariantIdx;
1920
use 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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// edition:2021
2+
3+
#[derive(Copy, Clone, PartialEq, Eq)]
4+
pub struct Opcode(pub u8);
5+
6+
impl Opcode {
7+
pub const OP1: Opcode = Opcode(0x1);
8+
}
9+
10+
pub fn example1(msg_type: Opcode) -> impl FnMut(&[u8]) {
11+
move |i| match msg_type {
12+
//~^ ERROR: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
13+
Opcode::OP1 => unimplemented!(),
14+
}
15+
}
16+
17+
#[derive(Copy, Clone, PartialEq, Eq)]
18+
pub struct Opcode2(Opcode);
19+
20+
impl Opcode2 {
21+
pub const OP2: Opcode2 = Opcode2(Opcode(0x1));
22+
}
23+
24+
25+
pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) {
26+
27+
move |i| match msg_type {
28+
//~^ ERROR: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
29+
Opcode2::OP2=> unimplemented!(),
30+
}
31+
}
32+
33+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0004]: non-exhaustive patterns: `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
2+
--> $DIR/issue-88331.rs:11:20
3+
|
4+
LL | pub struct Opcode(pub u8);
5+
| -------------------------- `Opcode` defined here
6+
...
7+
LL | move |i| match msg_type {
8+
| ^^^^^^^^ patterns `Opcode(0_u8)` and `Opcode(2_u8..=u8::MAX)` not covered
9+
|
10+
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
11+
= note: the matched value is of type `Opcode`
12+
13+
error[E0004]: non-exhaustive patterns: `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
14+
--> $DIR/issue-88331.rs:27:20
15+
|
16+
LL | pub struct Opcode2(Opcode);
17+
| --------------------------- `Opcode2` defined here
18+
...
19+
LL | move |i| match msg_type {
20+
| ^^^^^^^^ patterns `Opcode2(Opcode(0_u8))` and `Opcode2(Opcode(2_u8..=u8::MAX))` not covered
21+
|
22+
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
23+
= note: the matched value is of type `Opcode2`
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)