Auto merge of #79670 - Nadrieril:uninhabited-query, r=estebank

Turn type inhabitedness into a query to fix `exhaustive_patterns` perf

We measured in https://github.com/rust-lang/rust/pull/79394 that enabling the [`exhaustive_patterns` feature](https://github.com/rust-lang/rust/issues/51085) causes significant perf degradation. It was conjectured that the culprit is type inhabitedness checking, and [I hypothesized](https://github.com/rust-lang/rust/pull/79394#issuecomment-733861149) that turning this computation into a query would solve most of the problem.

This PR turns `tcx.is_ty_uninhabited_from` into a query, and I measured a 25% perf gain on the benchmark that stress-tests `exhaustiveness_patterns`. This more than compensates for the 30% perf hit I measured [when creating it](https://github.com/rust-lang/rustc-perf/pull/801). We'll have to measure enabling the feature again, but I suspect this fixes the perf regression entirely.
I'd like a perf run on this PR obviously.
I made small atomic commits to help reviewing. The first one is just me discovering the "revisions" feature of the testing framework.

I believe there's a push to move things out of `rustc_middle` because it's huge. I guess `inhabitedness/mod.rs` could be moved out, but it's quite small. `DefIdForest` might be movable somewhere too. I don't know what the policy is for that.

Ping `@camelid` since you were interested in following along
`@rustbot` modify labels: +A-exhaustiveness-checking
This commit is contained in:
bors 2021-01-12 22:58:42 +00:00
commit 058a710165
15 changed files with 563 additions and 522 deletions

View File

@ -1319,6 +1319,15 @@ rustc_queries! {
eval_always
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
}
/// Computes the set of modules from which this type is visibly uninhabited.
/// To check whether a type is uninhabited at all (not just from a given module), you could
/// check whether the forest is empty.
query type_uninhabited_from(
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> ty::inhabitedness::DefIdForest {
desc { "computing the inhabitedness of `{:?}`", key }
}
}
Other {

View File

@ -3,6 +3,9 @@ use crate::ty::{DefId, DefIdTree};
use rustc_hir::CRATE_HIR_ID;
use smallvec::SmallVec;
use std::mem;
use std::sync::Arc;
use DefIdForest::*;
/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
/// if a `DefId` representing a module is contained in the forest then all
@ -11,45 +14,77 @@ use std::mem;
///
/// This is used to represent a set of modules in which a type is visibly
/// uninhabited.
#[derive(Clone)]
pub struct DefIdForest {
/// The minimal set of `DefId`s required to represent the whole set.
/// If A and B are DefIds in the `DefIdForest`, and A is a descendant
/// of B, then only B will be in `root_ids`.
/// We use a `SmallVec` here because (for its use for caching inhabitedness)
/// it's rare that this will contain even two IDs.
root_ids: SmallVec<[DefId; 1]>,
///
/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
#[derive(Clone, HashStable)]
pub enum DefIdForest {
Empty,
Single(DefId),
/// This variant is very rare.
/// Invariant: >1 elements
/// We use `Arc` because this is used in the output of a query.
Multiple(Arc<[DefId]>),
}
/// Tests whether a slice of roots contains a given DefId.
#[inline]
fn slice_contains(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
}
impl<'tcx> DefIdForest {
/// Creates an empty forest.
pub fn empty() -> DefIdForest {
DefIdForest { root_ids: SmallVec::new() }
DefIdForest::Empty
}
/// Creates a forest consisting of a single tree representing the entire
/// crate.
#[inline]
pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
DefIdForest::from_id(crate_id.to_def_id())
DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
}
/// Creates a forest containing a `DefId` and all its descendants.
pub fn from_id(id: DefId) -> DefIdForest {
let mut root_ids = SmallVec::new();
root_ids.push(id);
DefIdForest { root_ids }
DefIdForest::Single(id)
}
fn as_slice(&self) -> &[DefId] {
match self {
Empty => &[],
Single(id) => std::slice::from_ref(id),
Multiple(root_ids) => root_ids,
}
}
// Only allocates in the rare `Multiple` case.
fn from_slice(root_ids: &[DefId]) -> DefIdForest {
match root_ids {
[] => Empty,
[id] => Single(*id),
_ => DefIdForest::Multiple(root_ids.into()),
}
}
/// Tests whether the forest is empty.
pub fn is_empty(&self) -> bool {
self.root_ids.is_empty()
match self {
Empty => true,
Single(..) | Multiple(..) => false,
}
}
/// Iterate over the set of roots.
fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
self.as_slice().iter().copied()
}
/// Tests whether the forest contains a given DefId.
pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
slice_contains(tcx, self.as_slice(), id)
}
/// Calculate the intersection of a collection of forests.
@ -58,35 +93,28 @@ impl<'tcx> DefIdForest {
I: IntoIterator<Item = DefIdForest>,
{
let mut iter = iter.into_iter();
let mut ret = if let Some(first) = iter.next() {
first
let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
SmallVec::from_slice(first.as_slice())
} else {
return DefIdForest::full(tcx);
};
let mut next_ret = SmallVec::new();
let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
for next_forest in iter {
// No need to continue if the intersection is already empty.
if ret.is_empty() {
break;
if ret.is_empty() || next_forest.is_empty() {
return DefIdForest::empty();
}
for id in ret.root_ids.drain(..) {
if next_forest.contains(tcx, id) {
next_ret.push(id);
} else {
old_ret.push(id);
}
}
ret.root_ids.extend(old_ret.drain(..));
// We keep the elements in `ret` that are also in `next_forest`.
next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
// We keep the elements in `next_forest` that are also in `ret`.
next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
mem::swap(&mut next_ret, &mut ret.root_ids);
next_ret.drain(..);
mem::swap(&mut next_ret, &mut ret);
next_ret.clear();
}
ret
DefIdForest::from_slice(&ret)
}
/// Calculate the union of a collection of forests.
@ -94,20 +122,26 @@ impl<'tcx> DefIdForest {
where
I: IntoIterator<Item = DefIdForest>,
{
let mut ret = DefIdForest::empty();
let mut next_ret = SmallVec::new();
let mut ret: SmallVec<[_; 1]> = SmallVec::new();
let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
for next_forest in iter {
next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));
// Union with the empty set is a no-op.
if next_forest.is_empty() {
continue;
}
for id in next_forest.root_ids {
if !next_ret.contains(&id) {
// We add everything in `ret` that is not in `next_forest`.
next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
// We add everything in `next_forest` that we haven't added yet.
for id in next_forest.iter() {
if !slice_contains(tcx, &next_ret, id) {
next_ret.push(id);
}
}
mem::swap(&mut next_ret, &mut ret.root_ids);
next_ret.drain(..);
mem::swap(&mut next_ret, &mut ret);
next_ret.clear();
}
ret
DefIdForest::from_slice(&ret)
}
}

View File

@ -6,7 +6,6 @@ use crate::ty::TyKind::*;
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::{DefId, SubstsRef};
use rustc_data_structures::stack::ensure_sufficient_stack;
mod def_id_forest;
@ -187,34 +186,46 @@ impl<'tcx> FieldDef {
impl<'tcx> TyS<'tcx> {
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
match *self.kind() {
Adt(def, substs) => {
ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
}
Never => DefIdForest::full(tcx),
Tuple(ref tys) => DefIdForest::union(
tcx,
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
),
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
Some(0) | None => DefIdForest::empty(),
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(1..) => ty.uninhabited_from(tcx, param_env),
},
// References to uninitialised memory are valid for any type, including
// uninhabited types, in unsafe code, so we treat all references as
// inhabited.
// The precise semantics of inhabitedness with respect to references is currently
// undecided.
Ref(..) => DefIdForest::empty(),
_ => DefIdForest::empty(),
}
fn uninhabited_from(
&'tcx self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
tcx.type_uninhabited_from(param_env.and(self))
}
}
// Query provider for `type_uninhabited_from`.
pub(crate) fn type_uninhabited_from<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> DefIdForest {
let ty = key.value;
let param_env = key.param_env;
match *ty.kind() {
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
Never => DefIdForest::full(tcx),
Tuple(ref tys) => DefIdForest::union(
tcx,
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
),
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
Some(0) | None => DefIdForest::empty(),
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(1..) => ty.uninhabited_from(tcx, param_env),
},
// References to uninitialised memory are valid for any type, including
// uninhabited types, in unsafe code, so we treat all references as
// inhabited.
// The precise semantics of inhabitedness with respect to references is currently
// undecided.
Ref(..) => DefIdForest::empty(),
_ => DefIdForest::empty(),
}
}

View File

@ -3155,6 +3155,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers {
trait_impls_of: trait_def::trait_impls_of_provider,
all_local_trait_impls: trait_def::all_local_trait_impls,
type_uninhabited_from: inhabitedness::type_uninhabited_from,
..*providers
};
}

View File

@ -1,2 +1,10 @@
#![crate_type = "rlib"]
pub enum EmptyForeignEnum {}
pub struct VisiblyUninhabitedForeignStruct {
pub field: EmptyForeignEnum,
}
pub struct SecretlyUninhabitedForeignStruct {
_priv: EmptyForeignEnum,
}

View File

@ -1,94 +1,94 @@
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:52:9
--> $DIR/empty-match.rs:37:9
|
LL | _ => {},
| ^
|
note: the lint level is defined here
--> $DIR/match-empty-exhaustive_patterns.rs:5:9
--> $DIR/empty-match.rs:8:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:55:9
--> $DIR/empty-match.rs:40:9
|
LL | _ if false => {},
| ^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:62:9
--> $DIR/empty-match.rs:47:9
|
LL | _ => {},
| ^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:65:9
--> $DIR/empty-match.rs:50:9
|
LL | _ if false => {},
| ^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:72:9
--> $DIR/empty-match.rs:57:9
|
LL | _ => {},
| ^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:75:9
--> $DIR/empty-match.rs:60:9
|
LL | _ if false => {},
| ^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:82:9
|
LL | Some(_) => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/match-empty-exhaustive_patterns.rs:86:9
|
LL | Some(_) => {}
| ^^^^^^^
error[E0004]: non-exhaustive patterns: type `u8` is non-empty
--> $DIR/match-empty-exhaustive_patterns.rs:89:18
--> $DIR/empty-match.rs:78:20
|
LL | match_empty!(0u8);
| ^^^
LL | match_no_arms!(0u8);
| ^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
--> $DIR/match-empty-exhaustive_patterns.rs:91:18
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
LL | struct NonEmptyStruct1;
| ----------------------- `NonEmptyStruct1` defined here
...
LL | match_empty!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyStruct`
= note: the matched value is of type `NonEmptyStruct1`
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
LL | struct NonEmptyStruct2(bool);
| ----------------------------- `NonEmptyStruct2` defined here
...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyStruct2`
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/match-empty-exhaustive_patterns.rs:93:18
--> $DIR/empty-match.rs:81:20
|
LL | / union NonEmptyUnion1 {
LL | | foo: (),
LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_empty!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyUnion1`
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/match-empty-exhaustive_patterns.rs:95:18
--> $DIR/empty-match.rs:82:20
|
LL | / union NonEmptyUnion2 {
LL | | foo: (),
@ -96,101 +96,107 @@ LL | | bar: (),
LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_empty!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyUnion2`
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:97:18
--> $DIR/empty-match.rs:83:20
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_empty!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
LL | match_no_arms!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:99:18
--> $DIR/empty-match.rs:84:20
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | Bar,
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum2` defined here
...
LL | match_empty!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
LL | match_no_arms!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty-exhaustive_patterns.rs:101:18
--> $DIR/empty-match.rs:85:20
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_empty!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
LL | match_no_arms!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:104:18
--> $DIR/empty-match.rs:87:24
|
LL | match_false!(0u8);
| ^^^ pattern `_` not covered
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` 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 `u8`
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:106:18
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
LL | struct NonEmptyStruct1;
| ----------------------- `NonEmptyStruct1` defined here
...
LL | match_false!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` 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 `NonEmptyStruct`
= note: the matched value is of type `NonEmptyStruct1`
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
LL | struct NonEmptyStruct2(bool);
| ----------------------------- `NonEmptyStruct2` defined here
...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` 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 `NonEmptyStruct2`
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:108:18
--> $DIR/empty-match.rs:90:24
|
LL | / union NonEmptyUnion1 {
LL | | foo: (),
LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_false!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` 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 `NonEmptyUnion1`
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:110:18
--> $DIR/empty-match.rs:91:24
|
LL | / union NonEmptyUnion2 {
LL | | foo: (),
@ -198,60 +204,54 @@ LL | | bar: (),
LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_false!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` 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 `NonEmptyUnion2`
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:112:18
--> $DIR/empty-match.rs:92:24
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_false!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty-exhaustive_patterns.rs:114:18
--> $DIR/empty-match.rs:93:24
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | Bar,
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum2` defined here
...
LL | match_false!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty-exhaustive_patterns.rs:116:18
--> $DIR/empty-match.rs:94:24
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_false!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
LL | match_guarded_arm!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`

View File

@ -1,82 +1,94 @@
error: unreachable pattern
--> $DIR/match-empty.rs:51:9
--> $DIR/empty-match.rs:37:9
|
LL | _ => {},
| ^
|
note: the lint level is defined here
--> $DIR/match-empty.rs:4:9
--> $DIR/empty-match.rs:8:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/match-empty.rs:54:9
--> $DIR/empty-match.rs:40:9
|
LL | _ if false => {},
| ^
error: unreachable pattern
--> $DIR/match-empty.rs:61:9
--> $DIR/empty-match.rs:47:9
|
LL | _ => {},
| ^
error: unreachable pattern
--> $DIR/match-empty.rs:64:9
--> $DIR/empty-match.rs:50:9
|
LL | _ if false => {},
| ^
error: unreachable pattern
--> $DIR/match-empty.rs:71:9
--> $DIR/empty-match.rs:57:9
|
LL | _ => {},
| ^
error: unreachable pattern
--> $DIR/match-empty.rs:74:9
--> $DIR/empty-match.rs:60:9
|
LL | _ if false => {},
| ^
error[E0004]: non-exhaustive patterns: type `u8` is non-empty
--> $DIR/match-empty.rs:89:18
--> $DIR/empty-match.rs:78:20
|
LL | match_empty!(0u8);
| ^^^
LL | match_no_arms!(0u8);
| ^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty
--> $DIR/match-empty.rs:91:18
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty
--> $DIR/empty-match.rs:79:20
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
LL | struct NonEmptyStruct1;
| ----------------------- `NonEmptyStruct1` defined here
...
LL | match_empty!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyStruct`
= note: the matched value is of type `NonEmptyStruct1`
error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty
--> $DIR/empty-match.rs:80:20
|
LL | struct NonEmptyStruct2(bool);
| ----------------------------- `NonEmptyStruct2` defined here
...
LL | match_no_arms!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyStruct2`
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty
--> $DIR/match-empty.rs:93:18
--> $DIR/empty-match.rs:81:20
|
LL | / union NonEmptyUnion1 {
LL | | foo: (),
LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_empty!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyUnion1`
error[E0004]: non-exhaustive patterns: type `NonEmptyUnion2` is non-empty
--> $DIR/match-empty.rs:95:18
--> $DIR/empty-match.rs:82:20
|
LL | / union NonEmptyUnion2 {
LL | | foo: (),
@ -84,101 +96,107 @@ LL | | bar: (),
LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_empty!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | match_no_arms!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `NonEmptyUnion2`
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty.rs:97:18
--> $DIR/empty-match.rs:83:20
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_empty!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
LL | match_no_arms!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty.rs:99:18
--> $DIR/empty-match.rs:84:20
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | Bar,
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum2` defined here
...
LL | match_empty!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
LL | match_no_arms!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty.rs:101:18
--> $DIR/empty-match.rs:85:20
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_empty!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
LL | match_no_arms!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/match-empty.rs:104:18
--> $DIR/empty-match.rs:87:24
|
LL | match_false!(0u8);
| ^^^ pattern `_` not covered
LL | match_guarded_arm!(0u8);
| ^^^ pattern `_` 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 `u8`
error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered
--> $DIR/match-empty.rs:106:18
error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered
--> $DIR/empty-match.rs:88:24
|
LL | struct NonEmptyStruct(bool);
| ---------------------------- `NonEmptyStruct` defined here
LL | struct NonEmptyStruct1;
| ----------------------- `NonEmptyStruct1` defined here
...
LL | match_false!(NonEmptyStruct(true));
| ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered
LL | match_guarded_arm!(NonEmptyStruct1);
| ^^^^^^^^^^^^^^^ pattern `NonEmptyStruct1` 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 `NonEmptyStruct`
= note: the matched value is of type `NonEmptyStruct1`
error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered
--> $DIR/empty-match.rs:89:24
|
LL | struct NonEmptyStruct2(bool);
| ----------------------------- `NonEmptyStruct2` defined here
...
LL | match_guarded_arm!(NonEmptyStruct2(true));
| ^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct2(_)` 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 `NonEmptyStruct2`
error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered
--> $DIR/match-empty.rs:108:18
--> $DIR/empty-match.rs:90:24
|
LL | / union NonEmptyUnion1 {
LL | | foo: (),
LL | | }
| |_- `NonEmptyUnion1` defined here
...
LL | match_false!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` not covered
LL | match_guarded_arm!((NonEmptyUnion1 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion1 { .. }` 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 `NonEmptyUnion1`
error[E0004]: non-exhaustive patterns: `NonEmptyUnion2 { .. }` not covered
--> $DIR/match-empty.rs:110:18
--> $DIR/empty-match.rs:91:24
|
LL | / union NonEmptyUnion2 {
LL | | foo: (),
@ -186,64 +204,58 @@ LL | | bar: (),
LL | | }
| |_- `NonEmptyUnion2` defined here
...
LL | match_false!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` not covered
LL | match_guarded_arm!((NonEmptyUnion2 { foo: () }));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyUnion2 { .. }` 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 `NonEmptyUnion2`
error[E0004]: non-exhaustive patterns: `Foo(_)` not covered
--> $DIR/match-empty.rs:112:18
--> $DIR/empty-match.rs:92:24
|
LL | / enum NonEmptyEnum1 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum1` defined here
...
LL | match_false!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered
LL | match_guarded_arm!(NonEmptyEnum1::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` 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 `NonEmptyEnum1`
error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered
--> $DIR/match-empty.rs:114:18
--> $DIR/empty-match.rs:93:24
|
LL | / enum NonEmptyEnum2 {
LL | | Foo(bool),
| | --- not covered
LL | |
LL | |
LL | | Bar,
| | --- not covered
LL | |
LL | |
LL | | }
| |_- `NonEmptyEnum2` defined here
...
LL | match_false!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered
LL | match_guarded_arm!(NonEmptyEnum2::Foo(true));
| ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` 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 `NonEmptyEnum2`
error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered
--> $DIR/match-empty.rs:116:18
--> $DIR/empty-match.rs:94:24
|
LL | / enum NonEmptyEnum5 {
LL | | V1, V2, V3, V4, V5,
LL | | }
| |_- `NonEmptyEnum5` defined here
...
LL | match_false!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered
LL | match_guarded_arm!(NonEmptyEnum5::V1);
| ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more 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 `NonEmptyEnum5`
error: aborting due to 20 previous errors
error: aborting due to 22 previous errors
For more information about this error, try `rustc --explain E0004`.

View File

@ -0,0 +1,95 @@
// aux-build:empty.rs
// revisions: normal exhaustive_patterns
//
// This tests a match with no arms on various types.
#![feature(never_type)]
#![feature(never_type_fallback)]
#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
#![deny(unreachable_patterns)]
extern crate empty;
enum EmptyEnum {}
struct NonEmptyStruct1;
struct NonEmptyStruct2(bool);
union NonEmptyUnion1 {
foo: (),
}
union NonEmptyUnion2 {
foo: (),
bar: (),
}
enum NonEmptyEnum1 {
Foo(bool),
}
enum NonEmptyEnum2 {
Foo(bool),
Bar,
}
enum NonEmptyEnum5 {
V1, V2, V3, V4, V5,
}
fn empty_enum(x: EmptyEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn never(x: !) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
macro_rules! match_no_arms {
($e:expr) => {
match $e {}
};
}
macro_rules! match_guarded_arm {
($e:expr) => {
match $e {
_ if false => {}
}
};
}
fn main() {
match_no_arms!(0u8); //~ ERROR type `u8` is non-empty
match_no_arms!(NonEmptyStruct1); //~ ERROR type `NonEmptyStruct1` is non-empty
match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty
match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty
match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty
match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
match_guarded_arm!(0u8); //~ ERROR `_` not covered
match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered
match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered
match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered
match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered
match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered
match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered
match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered
}

View File

@ -1,48 +0,0 @@
#![feature(exclusive_range_pattern)]
macro_rules! m {
($s:expr, $($t:tt)+) => {
match $s { $($t)+ => {} }
}
}
fn main() {
match 0usize {
//~^ ERROR non-exhaustive patterns
0 ..= usize::MAX => {}
}
match 0isize {
//~^ ERROR non-exhaustive patterns
isize::MIN ..= isize::MAX => {}
}
m!(0usize, 0..=usize::MAX);
//~^ ERROR non-exhaustive patterns
m!(0usize, 0..5 | 5..=usize::MAX);
//~^ ERROR non-exhaustive patterns
m!(0usize, 0..usize::MAX | usize::MAX);
//~^ ERROR non-exhaustive patterns
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
//~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..=isize::MAX);
//~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
//~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..isize::MAX | isize::MAX);
//~^ ERROR non-exhaustive patterns
m!((0isize, true), (isize::MIN..5, true)
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
//~^^ ERROR non-exhaustive patterns
match 0isize {
//~^ ERROR non-exhaustive patterns
isize::MIN ..= -1 => {}
0 => {}
1 ..= isize::MAX => {}
}
match 7usize {}
//~^ ERROR non-exhaustive patterns
}

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int-allow.rs:36:11
--> $DIR/pointer-sized-int.rs:48:11
|
LL | match 7usize {}
| ^^^^^^

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:10:11
--> $DIR/pointer-sized-int.rs:12:11
|
LL | match 0usize {
| ^^^^^^ pattern `_` not covered
@ -10,7 +10,7 @@ LL | match 0usize {
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:15:11
--> $DIR/pointer-sized-int.rs:17:11
|
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
@ -21,7 +21,7 @@ LL | match 0isize {
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:20:8
--> $DIR/pointer-sized-int.rs:22:8
|
LL | m!(0usize, 0..=usize::MAX);
| ^^^^^^ pattern `_` not covered
@ -32,7 +32,7 @@ LL | m!(0usize, 0..=usize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:22:8
--> $DIR/pointer-sized-int.rs:24:8
|
LL | m!(0usize, 0..5 | 5..=usize::MAX);
| ^^^^^^ pattern `_` not covered
@ -43,7 +43,7 @@ LL | m!(0usize, 0..5 | 5..=usize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:24:8
--> $DIR/pointer-sized-int.rs:26:8
|
LL | m!(0usize, 0..usize::MAX | usize::MAX);
| ^^^^^^ pattern `_` not covered
@ -54,7 +54,7 @@ LL | m!(0usize, 0..usize::MAX | usize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int-deny.rs:26:8
--> $DIR/pointer-sized-int.rs:28:8
|
LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
@ -63,7 +63,7 @@ LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::
= note: the matched value is of type `(usize, bool)`
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:29:8
--> $DIR/pointer-sized-int.rs:31:8
|
LL | m!(0isize, isize::MIN..=isize::MAX);
| ^^^^^^ pattern `_` not covered
@ -74,7 +74,7 @@ LL | m!(0isize, isize::MIN..=isize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:31:8
--> $DIR/pointer-sized-int.rs:33:8
|
LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
| ^^^^^^ pattern `_` not covered
@ -85,7 +85,7 @@ LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:33:8
--> $DIR/pointer-sized-int.rs:35:8
|
LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
| ^^^^^^ pattern `_` not covered
@ -96,7 +96,7 @@ LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX);
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error[E0004]: non-exhaustive patterns: `(_, _)` not covered
--> $DIR/pointer-sized-int-deny.rs:35:8
--> $DIR/pointer-sized-int.rs:37:8
|
LL | m!((0isize, true), (isize::MIN..5, true)
| ^^^^^^^^^^^^^^ pattern `(_, _)` not covered
@ -105,7 +105,7 @@ LL | m!((0isize, true), (isize::MIN..5, true)
= note: the matched value is of type `(isize, bool)`
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/pointer-sized-int-deny.rs:39:11
--> $DIR/pointer-sized-int.rs:41:11
|
LL | match 0isize {
| ^^^^^^ pattern `_` not covered
@ -116,7 +116,7 @@ LL | match 0isize {
= help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching
error[E0004]: non-exhaustive patterns: type `usize` is non-empty
--> $DIR/pointer-sized-int-deny.rs:46:11
--> $DIR/pointer-sized-int.rs:48:11
|
LL | match 7usize {}
| ^^^^^^

View File

@ -1,5 +1,6 @@
#![feature(precise_pointer_size_matching)]
// revisions: allow deny
#![feature(exclusive_range_pattern)]
#![cfg_attr(allow, feature(precise_pointer_size_matching))]
macro_rules! m {
($s:expr, $($t:tt)+) => {
@ -9,25 +10,36 @@ macro_rules! m {
fn main() {
match 0usize {
//[deny]~^ ERROR non-exhaustive patterns
0 ..= usize::MAX => {}
}
match 0isize {
//[deny]~^ ERROR non-exhaustive patterns
isize::MIN ..= isize::MAX => {}
}
m!(0usize, 0..=usize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0usize, 0..5 | 5..=usize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0usize, 0..usize::MAX | usize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false));
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..=isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..5 | 5..=isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!(0isize, isize::MIN..isize::MAX | isize::MAX);
//[deny]~^ ERROR non-exhaustive patterns
m!((0isize, true), (isize::MIN..5, true)
| (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false));
//[deny]~^^ ERROR non-exhaustive patterns
match 0isize {
//[deny]~^ ERROR non-exhaustive patterns
isize::MIN ..= -1 => {}
0 => {}
1 ..= isize::MAX => {}

View File

@ -1,118 +0,0 @@
// aux-build:empty.rs
#![feature(never_type)]
#![feature(never_type_fallback)]
#![feature(exhaustive_patterns)]
#![deny(unreachable_patterns)]
extern crate empty;
enum EmptyEnum {}
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
foo: (),
}
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
foo: (),
bar: (),
}
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
Foo(bool),
//~^ not covered
//~| not covered
}
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
Foo(bool),
//~^ not covered
//~| not covered
Bar,
//~^ not covered
//~| not covered
}
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
V1, V2, V3, V4, V5,
}
macro_rules! match_empty {
($e:expr) => {
match $e {}
};
}
macro_rules! match_false {
($e:expr) => {
match $e {
_ if false => {}
}
};
}
fn empty_enum(x: EmptyEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn never(x: !) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn main() {
match None::<!> {
None => {}
Some(_) => {} //~ ERROR unreachable pattern
}
match None::<EmptyEnum> {
None => {}
Some(_) => {} //~ ERROR unreachable pattern
}
match_empty!(0u8);
//~^ ERROR type `u8` is non-empty
match_empty!(NonEmptyStruct(true));
//~^ ERROR type `NonEmptyStruct` is non-empty
match_empty!((NonEmptyUnion1 { foo: () }));
//~^ ERROR type `NonEmptyUnion1` is non-empty
match_empty!((NonEmptyUnion2 { foo: () }));
//~^ ERROR type `NonEmptyUnion2` is non-empty
match_empty!(NonEmptyEnum1::Foo(true));
//~^ ERROR `Foo(_)` not covered
match_empty!(NonEmptyEnum2::Foo(true));
//~^ ERROR `Foo(_)` and `Bar` not covered
match_empty!(NonEmptyEnum5::V1);
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
match_false!(0u8);
//~^ ERROR `_` not covered
match_false!(NonEmptyStruct(true));
//~^ ERROR `NonEmptyStruct(_)` not covered
match_false!((NonEmptyUnion1 { foo: () }));
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
match_false!((NonEmptyUnion2 { foo: () }));
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
match_false!(NonEmptyEnum1::Foo(true));
//~^ ERROR `Foo(_)` not covered
match_false!(NonEmptyEnum2::Foo(true));
//~^ ERROR `Foo(_)` and `Bar` not covered
match_false!(NonEmptyEnum5::V1);
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
}

View File

@ -1,118 +0,0 @@
// aux-build:empty.rs
#![feature(never_type)]
#![feature(never_type_fallback)]
#![deny(unreachable_patterns)]
extern crate empty;
enum EmptyEnum {}
struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here
union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here
foo: (),
}
union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here
foo: (),
bar: (),
}
enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here
Foo(bool),
//~^ not covered
//~| not covered
}
enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here
Foo(bool),
//~^ not covered
//~| not covered
Bar,
//~^ not covered
//~| not covered
}
enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here
V1, V2, V3, V4, V5,
}
macro_rules! match_empty {
($e:expr) => {
match $e {}
};
}
macro_rules! match_false {
($e:expr) => {
match $e {
_ if false => {}
}
};
}
fn empty_enum(x: EmptyEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn empty_foreign_enum(x: empty::EmptyForeignEnum) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn never(x: !) {
match x {} // ok
match x {
_ => {}, //~ ERROR unreachable pattern
}
match x {
_ if false => {}, //~ ERROR unreachable pattern
}
}
fn main() {
// `exhaustive_patterns` is not on, so uninhabited branches are not detected as unreachable.
match None::<!> {
None => {}
Some(_) => {}
}
match None::<EmptyEnum> {
None => {}
Some(_) => {}
}
match_empty!(0u8);
//~^ ERROR type `u8` is non-empty
match_empty!(NonEmptyStruct(true));
//~^ ERROR type `NonEmptyStruct` is non-empty
match_empty!((NonEmptyUnion1 { foo: () }));
//~^ ERROR type `NonEmptyUnion1` is non-empty
match_empty!((NonEmptyUnion2 { foo: () }));
//~^ ERROR type `NonEmptyUnion2` is non-empty
match_empty!(NonEmptyEnum1::Foo(true));
//~^ ERROR `Foo(_)` not covered
match_empty!(NonEmptyEnum2::Foo(true));
//~^ ERROR `Foo(_)` and `Bar` not covered
match_empty!(NonEmptyEnum5::V1);
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
match_false!(0u8);
//~^ ERROR `_` not covered
match_false!(NonEmptyStruct(true));
//~^ ERROR `NonEmptyStruct(_)` not covered
match_false!((NonEmptyUnion1 { foo: () }));
//~^ ERROR `NonEmptyUnion1 { .. }` not covered
match_false!((NonEmptyUnion2 { foo: () }));
//~^ ERROR `NonEmptyUnion2 { .. }` not covered
match_false!(NonEmptyEnum1::Foo(true));
//~^ ERROR `Foo(_)` not covered
match_false!(NonEmptyEnum2::Foo(true));
//~^ ERROR `Foo(_)` and `Bar` not covered
match_false!(NonEmptyEnum5::V1);
//~^ ERROR `V1`, `V2`, `V3` and 2 more not covered
}

View File

@ -0,0 +1,143 @@
// check-pass
// aux-build:empty.rs
//
// This tests plays with matching and uninhabited types. This also serves as a test for the
// `tcx.is_ty_uninhabited_from()` function.
#![feature(never_type)]
#![feature(never_type_fallback)]
#![feature(exhaustive_patterns)]
#![deny(unreachable_patterns)]
macro_rules! assert_empty {
($ty:ty) => {
const _: () = {
fn assert_empty(x: $ty) {
match x {}
match Some(x) {
None => {}
}
}
};
};
}
macro_rules! assert_non_empty {
($ty:ty) => {
const _: () = {
fn assert_non_empty(x: $ty) {
match x {
_ => {}
}
match Some(x) {
None => {}
Some(_) => {}
}
}
};
};
}
extern crate empty;
assert_empty!(empty::EmptyForeignEnum);
assert_empty!(empty::VisiblyUninhabitedForeignStruct);
assert_non_empty!(empty::SecretlyUninhabitedForeignStruct);
enum Void {}
assert_empty!(Void);
enum Enum2 {
Foo(Void),
Bar(!),
}
assert_empty!(Enum2);
enum Enum3 {
Foo(Void),
Bar {
x: u64,
y: !,
},
}
assert_empty!(Enum3);
enum Enum4 {
Foo(u64),
Bar(!),
}
assert_non_empty!(Enum4);
struct Struct1(empty::EmptyForeignEnum);
assert_empty!(Struct1);
struct Struct2 {
x: u64,
y: !,
}
assert_empty!(Struct2);
union Union {
foo: !,
}
assert_non_empty!(Union);
assert_empty!((!, String));
assert_non_empty!(&'static !);
assert_non_empty!(&'static Struct1);
assert_non_empty!(&'static &'static &'static !);
assert_empty!([!; 1]);
assert_empty!([Void; 2]);
assert_non_empty!([!; 0]);
assert_non_empty!(&'static [!]);
mod visibility {
/// This struct can only be seen to be inhabited in modules `b`, `c` or `d`, because otherwise
/// the uninhabitedness of both `SecretlyUninhabited` structs is hidden.
struct SometimesEmptyStruct {
x: a::b::SecretlyUninhabited,
y: c::AlsoSecretlyUninhabited,
}
/// This enum can only be seen to be inhabited in module `d`.
enum SometimesEmptyEnum {
X(c::AlsoSecretlyUninhabited),
Y(c::d::VerySecretlyUninhabited),
}
mod a {
use super::*;
pub mod b {
use super::*;
pub struct SecretlyUninhabited {
_priv: !,
}
assert_empty!(SometimesEmptyStruct);
}
assert_non_empty!(SometimesEmptyStruct);
assert_non_empty!(SometimesEmptyEnum);
}
mod c {
use super::*;
pub struct AlsoSecretlyUninhabited {
_priv: ::Struct1,
}
assert_empty!(SometimesEmptyStruct);
assert_non_empty!(SometimesEmptyEnum);
pub mod d {
use super::*;
pub struct VerySecretlyUninhabited {
_priv: !,
}
assert_empty!(SometimesEmptyStruct);
assert_empty!(SometimesEmptyEnum);
}
}
assert_non_empty!(SometimesEmptyStruct);
assert_non_empty!(SometimesEmptyEnum);
}
fn main() {}