Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add missing const edge case #88390

Merged
merged 4 commits into from
Aug 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions compiler/rustc_typeck/src/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -836,3 +846,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 }
}
33 changes: 33 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/issue-88331.rs
Original file line number Diff line number Diff line change
@@ -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() {}
27 changes: 27 additions & 0 deletions src/test/ui/closures/2229_closure_analysis/issue-88331.stderr
Original file line number Diff line number Diff line change
@@ -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`.