From 622bfdb2fdfc3da9ca2959b5e9ae686b1c9ed249 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 2 Dec 2020 20:24:20 +0000 Subject: [PATCH 1/4] Deduplicate some tests using revisions --- ...=> empty-match.exhaustive_patterns.stderr} | 46 +++---- ...empty.stderr => empty-match.normal.stderr} | 42 +++---- ...-exhaustive_patterns.rs => empty-match.rs} | 7 +- .../integer-ranges/pointer-sized-int-deny.rs | 48 ------- ....stderr => pointer-sized-int.allow.stderr} | 2 +- ...y.stderr => pointer-sized-int.deny.stderr} | 24 ++-- ...ized-int-allow.rs => pointer-sized-int.rs} | 14 ++- src/test/ui/pattern/usefulness/match-empty.rs | 118 ------------------ 8 files changed, 74 insertions(+), 227 deletions(-) rename src/test/ui/pattern/usefulness/{match-empty-exhaustive_patterns.stderr => empty-match.exhaustive_patterns.stderr} (86%) rename src/test/ui/pattern/usefulness/{match-empty.stderr => empty-match.normal.stderr} (91%) rename src/test/ui/pattern/usefulness/{match-empty-exhaustive_patterns.rs => empty-match.rs} (91%) delete mode 100644 src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs rename src/test/ui/pattern/usefulness/integer-ranges/{pointer-sized-int-allow.stderr => pointer-sized-int.allow.stderr} (89%) rename src/test/ui/pattern/usefulness/integer-ranges/{pointer-sized-int-deny.stderr => pointer-sized-int.deny.stderr} (92%) rename src/test/ui/pattern/usefulness/integer-ranges/{pointer-sized-int-allow.rs => pointer-sized-int.rs} (60%) delete mode 100644 src/test/ui/pattern/usefulness/match-empty.rs diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr similarity index 86% rename from src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr rename to src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index 9d8b5f38e8cf5..a5c8af1f81467 100644 --- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,59 +1,59 @@ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:52:9 + --> $DIR/empty-match.rs:53:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/match-empty-exhaustive_patterns.rs:5:9 + --> $DIR/empty-match.rs:6:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:55:9 + --> $DIR/empty-match.rs:56:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:62:9 + --> $DIR/empty-match.rs:63:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:65:9 + --> $DIR/empty-match.rs:66:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:72:9 + --> $DIR/empty-match.rs:73:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:75:9 + --> $DIR/empty-match.rs:76:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:82:9 + --> $DIR/empty-match.rs:83:9 | LL | Some(_) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/match-empty-exhaustive_patterns.rs:86:9 + --> $DIR/empty-match.rs:87: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:90:18 | LL | match_empty!(0u8); | ^^^ @@ -62,7 +62,7 @@ LL | match_empty!(0u8); = 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 + --> $DIR/empty-match.rs:92:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -74,7 +74,7 @@ LL | match_empty!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/match-empty-exhaustive_patterns.rs:93:18 + --> $DIR/empty-match.rs:94:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -88,7 +88,7 @@ LL | match_empty!((NonEmptyUnion1 { foo: () })); = 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:96:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -103,7 +103,7 @@ LL | match_empty!((NonEmptyUnion2 { foo: () })); = 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:98:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -120,7 +120,7 @@ LL | match_empty!(NonEmptyEnum1::Foo(true)); = 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:100:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -141,7 +141,7 @@ LL | match_empty!(NonEmptyEnum2::Foo(true)); = 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:102:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -155,7 +155,7 @@ LL | match_empty!(NonEmptyEnum5::V1); = 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:105:18 | LL | match_false!(0u8); | ^^^ pattern `_` not covered @@ -164,7 +164,7 @@ LL | match_false!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:106:18 + --> $DIR/empty-match.rs:107:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -176,7 +176,7 @@ LL | match_false!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/match-empty-exhaustive_patterns.rs:108:18 + --> $DIR/empty-match.rs:109:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -190,7 +190,7 @@ LL | match_false!((NonEmptyUnion1 { foo: () })); = 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:111:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -205,7 +205,7 @@ LL | match_false!((NonEmptyUnion2 { foo: () })); = 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:113:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -222,7 +222,7 @@ LL | match_false!(NonEmptyEnum1::Foo(true)); = 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:115:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -243,7 +243,7 @@ LL | match_false!(NonEmptyEnum2::Foo(true)); = 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:117:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, diff --git a/src/test/ui/pattern/usefulness/match-empty.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr similarity index 91% rename from src/test/ui/pattern/usefulness/match-empty.stderr rename to src/test/ui/pattern/usefulness/empty-match.normal.stderr index 6065c552390e4..7db11f146b219 100644 --- a/src/test/ui/pattern/usefulness/match-empty.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,47 +1,47 @@ error: unreachable pattern - --> $DIR/match-empty.rs:51:9 + --> $DIR/empty-match.rs:53:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/match-empty.rs:4:9 + --> $DIR/empty-match.rs:6:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/match-empty.rs:54:9 + --> $DIR/empty-match.rs:56:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty.rs:61:9 + --> $DIR/empty-match.rs:63:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/match-empty.rs:64:9 + --> $DIR/empty-match.rs:66:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/match-empty.rs:71:9 + --> $DIR/empty-match.rs:73:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/match-empty.rs:74:9 + --> $DIR/empty-match.rs:76:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/match-empty.rs:89:18 + --> $DIR/empty-match.rs:90:18 | LL | match_empty!(0u8); | ^^^ @@ -50,7 +50,7 @@ LL | match_empty!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty - --> $DIR/match-empty.rs:91:18 + --> $DIR/empty-match.rs:92:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -62,7 +62,7 @@ LL | match_empty!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/match-empty.rs:93:18 + --> $DIR/empty-match.rs:94:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -76,7 +76,7 @@ LL | match_empty!((NonEmptyUnion1 { foo: () })); = 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:96:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -91,7 +91,7 @@ LL | match_empty!((NonEmptyUnion2 { foo: () })); = 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:98:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -108,7 +108,7 @@ LL | match_empty!(NonEmptyEnum1::Foo(true)); = 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:100:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -129,7 +129,7 @@ LL | match_empty!(NonEmptyEnum2::Foo(true)); = 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:102:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, @@ -143,7 +143,7 @@ LL | match_empty!(NonEmptyEnum5::V1); = 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:105:18 | LL | match_false!(0u8); | ^^^ pattern `_` not covered @@ -152,7 +152,7 @@ LL | match_false!(0u8); = note: the matched value is of type `u8` error[E0004]: non-exhaustive patterns: `NonEmptyStruct(_)` not covered - --> $DIR/match-empty.rs:106:18 + --> $DIR/empty-match.rs:107:18 | LL | struct NonEmptyStruct(bool); | ---------------------------- `NonEmptyStruct` defined here @@ -164,7 +164,7 @@ LL | match_false!(NonEmptyStruct(true)); = note: the matched value is of type `NonEmptyStruct` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/match-empty.rs:108:18 + --> $DIR/empty-match.rs:109:18 | LL | / union NonEmptyUnion1 { LL | | foo: (), @@ -178,7 +178,7 @@ LL | match_false!((NonEmptyUnion1 { foo: () })); = 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:111:18 | LL | / union NonEmptyUnion2 { LL | | foo: (), @@ -193,7 +193,7 @@ LL | match_false!((NonEmptyUnion2 { foo: () })); = 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:113:18 | LL | / enum NonEmptyEnum1 { LL | | Foo(bool), @@ -210,7 +210,7 @@ LL | match_false!(NonEmptyEnum1::Foo(true)); = 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:115:18 | LL | / enum NonEmptyEnum2 { LL | | Foo(bool), @@ -231,7 +231,7 @@ LL | match_false!(NonEmptyEnum2::Foo(true)); = 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:117:18 | LL | / enum NonEmptyEnum5 { LL | | V1, V2, V3, V4, V5, diff --git a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs b/src/test/ui/pattern/usefulness/empty-match.rs similarity index 91% rename from src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs rename to src/test/ui/pattern/usefulness/empty-match.rs index c5c3a214f9aff..98d8ac180026d 100644 --- a/src/test/ui/pattern/usefulness/match-empty-exhaustive_patterns.rs +++ b/src/test/ui/pattern/usefulness/empty-match.rs @@ -1,7 +1,8 @@ // aux-build:empty.rs +// revisions: normal exhaustive_patterns #![feature(never_type)] #![feature(never_type_fallback)] -#![feature(exhaustive_patterns)] +#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))] #![deny(unreachable_patterns)] extern crate empty; @@ -79,11 +80,11 @@ fn never(x: !) { fn main() { match None:: { None => {} - Some(_) => {} //~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match None:: { None => {} - Some(_) => {} //~ ERROR unreachable pattern + Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern } match_empty!(0u8); diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs deleted file mode 100644 index 9292f22e09e05..0000000000000 --- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.rs +++ /dev/null @@ -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 -} diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr similarity index 89% rename from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr rename to src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr index 0b3c65166ee18..2563293458379 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr @@ -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 {} | ^^^^^^ diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr similarity index 92% rename from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr rename to src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr index 9d566b0e7751f..e8ac9f3cfe156 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-deny.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -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 {} | ^^^^^^ diff --git a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs similarity index 60% rename from src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs rename to src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs index 6173053cc4f3c..1ed18c2676358 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int-allow.rs +++ b/src/test/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs @@ -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 => {} diff --git a/src/test/ui/pattern/usefulness/match-empty.rs b/src/test/ui/pattern/usefulness/match-empty.rs deleted file mode 100644 index 10ea2a10406e3..0000000000000 --- a/src/test/ui/pattern/usefulness/match-empty.rs +++ /dev/null @@ -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:: { - 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 -} From b82f149d08a0afcc17afa54f5bb3c7031babd44a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 2 Dec 2020 23:11:29 +0000 Subject: [PATCH 2/4] Add tests for uninhabited types --- .../ui/pattern/usefulness/auxiliary/empty.rs | 8 + .../empty-match.exhaustive_patterns.stderr | 160 +++++++++--------- .../usefulness/empty-match.normal.stderr | 152 +++++++++-------- src/test/ui/pattern/usefulness/empty-match.rs | 100 +++++------ src/test/ui/pattern/usefulness/uninhabited.rs | 143 ++++++++++++++++ 5 files changed, 351 insertions(+), 212 deletions(-) create mode 100644 src/test/ui/pattern/usefulness/uninhabited.rs diff --git a/src/test/ui/pattern/usefulness/auxiliary/empty.rs b/src/test/ui/pattern/usefulness/auxiliary/empty.rs index 0b0719f48ee02..29a03c9e8b50c 100644 --- a/src/test/ui/pattern/usefulness/auxiliary/empty.rs +++ b/src/test/ui/pattern/usefulness/auxiliary/empty.rs @@ -1,2 +1,10 @@ #![crate_type = "rlib"] pub enum EmptyForeignEnum {} + +pub struct VisiblyUninhabitedForeignStruct { + pub field: EmptyForeignEnum, +} + +pub struct SecretlyUninhabitedForeignStruct { + _priv: EmptyForeignEnum, +} diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index a5c8af1f81467..b99386e74020e 100644 --- a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -1,94 +1,94 @@ error: unreachable pattern - --> $DIR/empty-match.rs:53:9 + --> $DIR/empty-match.rs:37:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/empty-match.rs:6:9 + --> $DIR/empty-match.rs:8:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:56:9 + --> $DIR/empty-match.rs:40:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:63:9 + --> $DIR/empty-match.rs:47:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:66:9 + --> $DIR/empty-match.rs:50:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:73:9 + --> $DIR/empty-match.rs:57:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:60:9 | LL | _ if false => {}, | ^ -error: unreachable pattern - --> $DIR/empty-match.rs:83:9 +error[E0004]: non-exhaustive patterns: type `u8` is non-empty + --> $DIR/empty-match.rs:78:20 | -LL | Some(_) => {} - | ^^^^^^^ - -error: unreachable pattern - --> $DIR/empty-match.rs:87:9 +LL | match_no_arms!(0u8); + | ^^^ | -LL | Some(_) => {} - | ^^^^^^^ + = 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 `u8` is non-empty - --> $DIR/empty-match.rs:90:18 +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct1` is non-empty + --> $DIR/empty-match.rs:79:20 | -LL | match_empty!(0u8); - | ^^^ +LL | struct NonEmptyStruct1; + | ----------------------- `NonEmptyStruct1` defined here +... +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 `u8` + = note: the matched value is of type `NonEmptyStruct1` -error[E0004]: non-exhaustive patterns: type `NonEmptyStruct` is non-empty - --> $DIR/empty-match.rs:92:18 +error[E0004]: non-exhaustive patterns: type `NonEmptyStruct2` is non-empty + --> $DIR/empty-match.rs:80:20 | -LL | struct NonEmptyStruct(bool); - | ---------------------------- `NonEmptyStruct` defined here +LL | struct NonEmptyStruct2(bool); + | ----------------------------- `NonEmptyStruct2` defined here ... -LL | match_empty!(NonEmptyStruct(true)); - | ^^^^^^^^^^^^^^^^^^^^ +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 `NonEmptyStruct` + = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: type `NonEmptyUnion1` is non-empty - --> $DIR/empty-match.rs:94: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/empty-match.rs:96: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/empty-match.rs:98: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/empty-match.rs:100: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/empty-match.rs:102: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/empty-match.rs:105: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/empty-match.rs:107:18 +error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered + --> $DIR/empty-match.rs:88:24 + | +LL | struct NonEmptyStruct1; + | ----------------------- `NonEmptyStruct1` defined here +... +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 `NonEmptyStruct1` + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered + --> $DIR/empty-match.rs:89:24 | -LL | struct NonEmptyStruct(bool); - | ---------------------------- `NonEmptyStruct` defined here +LL | struct NonEmptyStruct2(bool); + | ----------------------------- `NonEmptyStruct2` defined here ... -LL | match_false!(NonEmptyStruct(true)); - | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered +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 `NonEmptyStruct` + = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:109: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/empty-match.rs:111: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/empty-match.rs:113: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/empty-match.rs:115: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/empty-match.rs:117: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` diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr index 7db11f146b219..b99386e74020e 100644 --- a/src/test/ui/pattern/usefulness/empty-match.normal.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr @@ -1,82 +1,94 @@ error: unreachable pattern - --> $DIR/empty-match.rs:53:9 + --> $DIR/empty-match.rs:37:9 | LL | _ => {}, | ^ | note: the lint level is defined here - --> $DIR/empty-match.rs:6:9 + --> $DIR/empty-match.rs:8:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/empty-match.rs:56:9 + --> $DIR/empty-match.rs:40:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:63:9 + --> $DIR/empty-match.rs:47:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:66:9 + --> $DIR/empty-match.rs:50:9 | LL | _ if false => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:73:9 + --> $DIR/empty-match.rs:57:9 | LL | _ => {}, | ^ error: unreachable pattern - --> $DIR/empty-match.rs:76:9 + --> $DIR/empty-match.rs:60:9 | LL | _ if false => {}, | ^ error[E0004]: non-exhaustive patterns: type `u8` is non-empty - --> $DIR/empty-match.rs:90: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/empty-match.rs:92: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/empty-match.rs:94: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/empty-match.rs:96: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/empty-match.rs:98: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/empty-match.rs:100: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/empty-match.rs:102: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/empty-match.rs:105: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/empty-match.rs:107:18 +error[E0004]: non-exhaustive patterns: `NonEmptyStruct1` not covered + --> $DIR/empty-match.rs:88:24 + | +LL | struct NonEmptyStruct1; + | ----------------------- `NonEmptyStruct1` defined here +... +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 `NonEmptyStruct1` + +error[E0004]: non-exhaustive patterns: `NonEmptyStruct2(_)` not covered + --> $DIR/empty-match.rs:89:24 | -LL | struct NonEmptyStruct(bool); - | ---------------------------- `NonEmptyStruct` defined here +LL | struct NonEmptyStruct2(bool); + | ----------------------------- `NonEmptyStruct2` defined here ... -LL | match_false!(NonEmptyStruct(true)); - | ^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyStruct(_)` not covered +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 `NonEmptyStruct` + = note: the matched value is of type `NonEmptyStruct2` error[E0004]: non-exhaustive patterns: `NonEmptyUnion1 { .. }` not covered - --> $DIR/empty-match.rs:109: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/empty-match.rs:111: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/empty-match.rs:113: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/empty-match.rs:115: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/empty-match.rs:117: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`. diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs index 98d8ac180026d..8110ec013d7c1 100644 --- a/src/test/ui/pattern/usefulness/empty-match.rs +++ b/src/test/ui/pattern/usefulness/empty-match.rs @@ -1,5 +1,7 @@ // 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))] @@ -9,44 +11,26 @@ extern crate empty; enum EmptyEnum {} -struct NonEmptyStruct(bool); //~ `NonEmptyStruct` defined here -union NonEmptyUnion1 { //~ `NonEmptyUnion1` defined here +struct NonEmptyStruct1; +struct NonEmptyStruct2(bool); +union NonEmptyUnion1 { foo: (), } -union NonEmptyUnion2 { //~ `NonEmptyUnion2` defined here +union NonEmptyUnion2 { foo: (), bar: (), } -enum NonEmptyEnum1 { //~ `NonEmptyEnum1` defined here +enum NonEmptyEnum1 { Foo(bool), - //~^ not covered - //~| not covered } -enum NonEmptyEnum2 { //~ `NonEmptyEnum2` defined here +enum NonEmptyEnum2 { Foo(bool), - //~^ not covered - //~| not covered Bar, - //~^ not covered - //~| not covered } -enum NonEmptyEnum5 { //~ `NonEmptyEnum5` defined here +enum NonEmptyEnum5 { 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 { @@ -77,43 +61,35 @@ fn never(x: !) { } } -fn main() { - match None:: { - None => {} - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - } - match None:: { - None => {} - Some(_) => {} //[exhaustive_patterns]~ ERROR unreachable pattern - } +macro_rules! match_no_arms { + ($e:expr) => { + match $e {} + }; +} +macro_rules! match_guarded_arm { + ($e:expr) => { + match $e { + _ if false => {} + } + }; +} - 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 +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_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 + 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 } diff --git a/src/test/ui/pattern/usefulness/uninhabited.rs b/src/test/ui/pattern/usefulness/uninhabited.rs new file mode 100644 index 0000000000000..77cd0f4005e95 --- /dev/null +++ b/src/test/ui/pattern/usefulness/uninhabited.rs @@ -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() {} From 8598c9f6e53571d449ebf521fca1be4af9af1be6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 3 Dec 2020 00:25:04 +0000 Subject: [PATCH 3/4] Turn type inhabitedness into a query --- compiler/rustc_middle/src/query/mod.rs | 9 +++ .../src/ty/inhabitedness/def_id_forest.rs | 11 +++- .../rustc_middle/src/ty/inhabitedness/mod.rs | 66 +++++++++++-------- compiler/rustc_middle/src/ty/mod.rs | 1 + 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1e836d0a84253..418ae2ddfc736 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1308,6 +1308,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>> + ) -> Arc { + desc { "computing the inhabitedness of `{:?}`", key } + } } Other { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index d9aebfc8293b6..50fcd51b78cf7 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -11,7 +11,7 @@ use std::mem; /// /// This is used to represent a set of modules in which a type is visibly /// uninhabited. -#[derive(Clone)] +#[derive(Clone, HashStable)] 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 @@ -72,6 +72,9 @@ impl<'tcx> DefIdForest { break; } + // `next_ret` and `old_ret` are empty here. + // We keep the elements in `ret` that are also in `next_forest`. Those that aren't are + // put back in `ret` via `old_ret`. for id in ret.root_ids.drain(..) { if next_forest.contains(tcx, id) { next_ret.push(id); @@ -81,7 +84,13 @@ impl<'tcx> DefIdForest { } ret.root_ids.extend(old_ret.drain(..)); + // We keep the elements in `next_forest` that are also in `ret`. + // You'd think this is not needed because `next_ret` already contains `ret \inter + // next_forest`. But those aren't just sets of things. If `ret = [a]`, `next_forest = + // [b]` and `b` is a submodule of `a`, then `b` belongs in the intersection but we + // didn't catch it in the loop above. next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id))); + // `next_ret` now contains the intersection of the original `ret` and `next_forest`. mem::swap(&mut next_ret, &mut ret.root_ids); next_ret.drain(..); diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 2f7707b9498ad..9dc309e2ab559 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -6,7 +6,8 @@ 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; + +use std::sync::Arc; mod def_id_forest; @@ -187,34 +188,47 @@ 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)) - } + fn uninhabited_from( + &'tcx self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> DefIdForest { + tcx.type_uninhabited_from(param_env.and(self)).as_ref().clone() + } +} - Never => DefIdForest::full(tcx), +// Query provider for `type_uninhabited_from`. +pub(crate) fn type_uninhabited_from<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, +) -> Arc { + let ty = key.value; + let param_env = key.param_env; + let forest = match *ty.kind() { + Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), - Tuple(ref tys) => DefIdForest::union( - tcx, - tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), - ), + Never => DefIdForest::full(tcx), - 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), - }, + Tuple(ref tys) => DefIdForest::union( + tcx, + tys.iter().map(|ty| ty.expect_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(), + 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), + }, - _ => DefIdForest::empty(), - } - } + // 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(), + }; + Arc::new(forest) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 94186d490c3c2..b2448571b31ee 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -3146,6 +3146,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 }; } From e608d8f4e5e8e33b5d480323596d2aeabd129e4f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 3 Dec 2020 01:52:24 +0000 Subject: [PATCH 4/4] Make `DefIdForest` cheaper to clone Since `DefIdForest` contains 0 or 1 elements the large majority of the time, by allocating only in the >1 case we avoid almost all allocations, compared to `Arc>`. This shaves off 0.2% on the benchmark that stresses uninhabitedness checking. --- compiler/rustc_middle/src/query/mod.rs | 2 +- .../src/ty/inhabitedness/def_id_forest.rs | 127 +++++++++++------- .../rustc_middle/src/ty/inhabitedness/mod.rs | 11 +- 3 files changed, 81 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 418ae2ddfc736..2f1e0b391561b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1314,7 +1314,7 @@ rustc_queries! { /// check whether the forest is empty. query type_uninhabited_from( key: ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Arc { + ) -> ty::inhabitedness::DefIdForest { desc { "computing the inhabitedness of `{:?}`", key } } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs index 50fcd51b78cf7..03c8963b0907e 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs @@ -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. +/// +/// 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 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]>, +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 + '_ { + 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,44 +93,28 @@ impl<'tcx> DefIdForest { I: IntoIterator, { 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(); } - // `next_ret` and `old_ret` are empty here. - // We keep the elements in `ret` that are also in `next_forest`. Those that aren't are - // put back in `ret` via `old_ret`. - 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`. - // You'd think this is not needed because `next_ret` already contains `ret \inter - // next_forest`. But those aren't just sets of things. If `ret = [a]`, `next_forest = - // [b]` and `b` is a submodule of `a`, then `b` belongs in the intersection but we - // didn't catch it in the loop above. - next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id))); - // `next_ret` now contains the intersection of the original `ret` and `next_forest`. - - mem::swap(&mut next_ret, &mut ret.root_ids); - next_ret.drain(..); + next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id))); + + mem::swap(&mut next_ret, &mut ret); + next_ret.clear(); } - ret + DefIdForest::from_slice(&ret) } /// Calculate the union of a collection of forests. @@ -103,20 +122,26 @@ impl<'tcx> DefIdForest { where I: IntoIterator, { - 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) } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 9dc309e2ab559..119cb135046db 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -7,8 +7,6 @@ use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; use crate::ty::{AdtKind, Visibility}; use crate::ty::{DefId, SubstsRef}; -use std::sync::Arc; - mod def_id_forest; // The methods in this module calculate `DefIdForest`s of modules in which a @@ -193,7 +191,7 @@ impl<'tcx> TyS<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> DefIdForest { - tcx.type_uninhabited_from(param_env.and(self)).as_ref().clone() + tcx.type_uninhabited_from(param_env.and(self)) } } @@ -201,10 +199,10 @@ impl<'tcx> TyS<'tcx> { pub(crate) fn type_uninhabited_from<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, -) -> Arc { +) -> DefIdForest { let ty = key.value; let param_env = key.param_env; - let forest = match *ty.kind() { + match *ty.kind() { Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), Never => DefIdForest::full(tcx), @@ -229,6 +227,5 @@ pub(crate) fn type_uninhabited_from<'tcx>( Ref(..) => DefIdForest::empty(), _ => DefIdForest::empty(), - }; - Arc::new(forest) + } }