Skip to content

Commit e57ed0d

Browse files
authored
Rollup merge of #56362 - varkor:stabilise-exhaustive-integer-patterns, r=nikomatsakis
Stabilise exhaustive integer patterns This is dependent on the FCP for rust-lang/rfcs#2591 being completed, but that should happen tomorrow, so there's little harm in opening this PR early. Closes #50907.
2 parents a88feab + ed64b19 commit e57ed0d

24 files changed

+194
-113
lines changed

src/librustc/ty/sty.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
17871787
}
17881788
}
17891789

1790+
pub fn is_pointer_sized(&self) -> bool {
1791+
match self.sty {
1792+
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true,
1793+
_ => false,
1794+
}
1795+
}
1796+
17901797
pub fn is_machine(&self) -> bool {
17911798
match self.sty {
17921799
Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => false,

src/librustc_mir/hair/pattern/_match.rs

+30-26
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,6 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
584584
-> Vec<Constructor<'tcx>>
585585
{
586586
debug!("all_constructors({:?})", pcx.ty);
587-
let exhaustive_integer_patterns = cx.tcx.features().exhaustive_integer_patterns;
588587
let ctors = match pcx.ty.sty {
589588
ty::Bool => {
590589
[true, false].iter().map(|&b| {
@@ -614,7 +613,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
614613
.map(|v| Variant(v.did))
615614
.collect()
616615
}
617-
ty::Char if exhaustive_integer_patterns => {
616+
ty::Char => {
618617
vec![
619618
// The valid Unicode Scalar Value ranges.
620619
ConstantRange('\u{0000}' as u128,
@@ -629,14 +628,14 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
629628
),
630629
]
631630
}
632-
ty::Int(ity) if exhaustive_integer_patterns => {
631+
ty::Int(ity) => {
633632
// FIXME(49937): refactor these bit manipulations into interpret.
634633
let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
635634
let min = 1u128 << (bits - 1);
636635
let max = (1u128 << (bits - 1)) - 1;
637636
vec![ConstantRange(min, max, pcx.ty, RangeEnd::Included)]
638637
}
639-
ty::Uint(uty) if exhaustive_integer_patterns => {
638+
ty::Uint(uty) => {
640639
// FIXME(49937): refactor these bit manipulations into interpret.
641640
let bits = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size().bits() as u128;
642641
let max = !0u128 >> (128 - bits);
@@ -775,8 +774,17 @@ impl<'tcx> IntRange<'tcx> {
775774
fn from_ctor(tcx: TyCtxt<'_, 'tcx, 'tcx>,
776775
ctor: &Constructor<'tcx>)
777776
-> Option<IntRange<'tcx>> {
777+
// Floating-point ranges are permitted and we don't want
778+
// to consider them when constructing integer ranges.
779+
fn is_integral<'tcx>(ty: Ty<'tcx>) -> bool {
780+
match ty.sty {
781+
ty::Char | ty::Int(_) | ty::Uint(_) => true,
782+
_ => false,
783+
}
784+
}
785+
778786
match ctor {
779-
ConstantRange(lo, hi, ty, end) => {
787+
ConstantRange(lo, hi, ty, end) if is_integral(ty) => {
780788
// Perform a shift if the underlying types are signed,
781789
// which makes the interval arithmetic simpler.
782790
let bias = IntRange::signed_bias(tcx, ty);
@@ -789,7 +797,7 @@ impl<'tcx> IntRange<'tcx> {
789797
Some(IntRange { range: lo..=(hi - offset), ty })
790798
}
791799
}
792-
ConstantValue(val) => {
800+
ConstantValue(val) if is_integral(val.ty) => {
793801
let ty = val.ty;
794802
if let Some(val) = val.assert_bits(tcx, ty::ParamEnv::empty().and(ty)) {
795803
let bias = IntRange::signed_bias(tcx, ty);
@@ -799,9 +807,7 @@ impl<'tcx> IntRange<'tcx> {
799807
None
800808
}
801809
}
802-
Single | Variant(_) | Slice(_) => {
803-
None
804-
}
810+
_ => None,
805811
}
806812
}
807813

@@ -933,12 +939,10 @@ fn compute_missing_ctors<'a, 'tcx: 'a>(
933939
// If a constructor appears in a `match` arm, we can
934940
// eliminate it straight away.
935941
refined_ctors = vec![]
936-
} else if tcx.features().exhaustive_integer_patterns {
937-
if let Some(interval) = IntRange::from_ctor(tcx, used_ctor) {
938-
// Refine the required constructors for the type by subtracting
939-
// the range defined by the current constructor pattern.
940-
refined_ctors = interval.subtract_from(tcx, refined_ctors);
941-
}
942+
} else if let Some(interval) = IntRange::from_ctor(tcx, used_ctor) {
943+
// Refine the required constructors for the type by subtracting
944+
// the range defined by the current constructor pattern.
945+
refined_ctors = interval.subtract_from(tcx, refined_ctors);
942946
}
943947

944948
// If the constructor patterns that have been considered so far
@@ -1094,7 +1098,8 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
10941098

10951099
// For privately empty and non-exhaustive enums, we work as if there were an "extra"
10961100
// `_` constructor for the type, so we can never match over all constructors.
1097-
let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive;
1101+
let is_non_exhaustive = is_privately_empty || is_declared_nonexhaustive ||
1102+
(pcx.ty.is_pointer_sized() && !cx.tcx.features().precise_pointer_size_matching);
10981103

10991104
if cheap_missing_ctors == MissingCtors::Empty && !is_non_exhaustive {
11001105
split_grouped_constructors(cx.tcx, all_ctors, matrix, pcx.ty).into_iter().map(|c| {
@@ -1390,17 +1395,16 @@ fn slice_pat_covered_by_constructor<'tcx>(
13901395
// Whether to evaluate a constructor using exhaustive integer matching. This is true if the
13911396
// constructor is a range or constant with an integer type.
13921397
fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Constructor<'tcx>) -> bool {
1393-
if tcx.features().exhaustive_integer_patterns {
1394-
let ty = match ctor {
1395-
ConstantValue(value) => value.ty,
1396-
ConstantRange(_, _, ty, _) => ty,
1397-
_ => return false,
1398-
};
1399-
if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty {
1400-
return true;
1401-
}
1398+
let ty = match ctor {
1399+
ConstantValue(value) => value.ty,
1400+
ConstantRange(_, _, ty, _) => ty,
1401+
_ => return false,
1402+
};
1403+
if let ty::Char | ty::Int(_) | ty::Uint(_) = ty.sty {
1404+
!ty.is_pointer_sized() || tcx.features().precise_pointer_size_matching
1405+
} else {
1406+
false
14021407
}
1403-
false
14041408
}
14051409

14061410
/// For exhaustive integer matching, some constructors are grouped within other constructors

src/libsyntax/feature_gate.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,8 @@ declare_features! (
439439
// 'a: { break 'a; }
440440
(active, label_break_value, "1.28.0", Some(48594), None),
441441

442-
// Integer match exhaustiveness checking
443-
(active, exhaustive_integer_patterns, "1.30.0", Some(50907), None),
442+
// Exhaustive pattern matching on `usize` and `isize`.
443+
(active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
444444

445445
// #[doc(keyword = "...")]
446446
(active, doc_keyword, "1.28.0", Some(51315), None),
@@ -683,6 +683,8 @@ declare_features! (
683683
(accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None),
684684
// Allows use of the :literal macro fragment specifier (RFC 1576)
685685
(accepted, macro_literal_matcher, "1.31.0", Some(35625), None),
686+
// Integer match exhaustiveness checking (RFC 2591)
687+
(accepted, exhaustive_integer_patterns, "1.32.0", Some(50907), None),
686688
// Use `?` as the Kleene "at most one" operator
687689
(accepted, macro_at_most_once_rep, "1.32.0", Some(48075), None),
688690
// `Self` struct constructor (RFC 2302)

src/test/ui/consts/const-match-check.eval1.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `_` not covered
1+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
22
--> $DIR/const-match-check.rs:35:15
33
|
44
LL | A = { let 0 = 0; 0 },
5-
| ^ pattern `_` not covered
5+
| ^ pattern `-2147483648i32..=-1i32` not covered
66

77
error: aborting due to previous error
88

src/test/ui/consts/const-match-check.eval2.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `_` not covered
1+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
22
--> $DIR/const-match-check.rs:41:24
33
|
44
LL | let x: [i32; { let 0 = 0; 0 }] = [];
5-
| ^ pattern `_` not covered
5+
| ^ pattern `-2147483648i32..=-1i32` not covered
66

77
error: aborting due to previous error
88

src/test/ui/consts/const-match-check.matchck.stderr

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
error[E0005]: refutable pattern in local binding: `_` not covered
1+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
22
--> $DIR/const-match-check.rs:14:22
33
|
44
LL | const X: i32 = { let 0 = 0; 0 };
5-
| ^ pattern `_` not covered
5+
| ^ pattern `-2147483648i32..=-1i32` not covered
66

7-
error[E0005]: refutable pattern in local binding: `_` not covered
7+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
88
--> $DIR/const-match-check.rs:18:23
99
|
1010
LL | static Y: i32 = { let 0 = 0; 0 };
11-
| ^ pattern `_` not covered
11+
| ^ pattern `-2147483648i32..=-1i32` not covered
1212

13-
error[E0005]: refutable pattern in local binding: `_` not covered
13+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
1414
--> $DIR/const-match-check.rs:23:26
1515
|
1616
LL | const X: i32 = { let 0 = 0; 0 };
17-
| ^ pattern `_` not covered
17+
| ^ pattern `-2147483648i32..=-1i32` not covered
1818

19-
error[E0005]: refutable pattern in local binding: `_` not covered
19+
error[E0005]: refutable pattern in local binding: `-2147483648i32..=-1i32` not covered
2020
--> $DIR/const-match-check.rs:29:26
2121
|
2222
LL | const X: i32 = { let 0 = 0; 0 };
23-
| ^ pattern `_` not covered
23+
| ^ pattern `-2147483648i32..=-1i32` not covered
2424

2525
error: aborting due to 4 previous errors
2626

src/test/ui/consts/const-pattern-irrefutable.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use foo::d;
1919
const a: u8 = 2;
2020

2121
fn main() {
22-
let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
23-
let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
24-
let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
22+
let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
23+
let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
24+
let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
2525
fn f() {} // Check that the `NOTE`s still work with an item here (c.f. issue #35115).
2626
}

src/test/ui/consts/const-pattern-irrefutable.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
error[E0005]: refutable pattern in local binding: `_` not covered
1+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
22
--> $DIR/const-pattern-irrefutable.rs:22:9
33
|
4-
LL | let a = 4; //~ ERROR refutable pattern in local binding: `_` not covered
4+
LL | let a = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
55
| ^ interpreted as a constant pattern, not new variable
66

7-
error[E0005]: refutable pattern in local binding: `_` not covered
7+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
88
--> $DIR/const-pattern-irrefutable.rs:23:9
99
|
10-
LL | let c = 4; //~ ERROR refutable pattern in local binding: `_` not covered
10+
LL | let c = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
1111
| ^ interpreted as a constant pattern, not new variable
1212

13-
error[E0005]: refutable pattern in local binding: `_` not covered
13+
error[E0005]: refutable pattern in local binding: `0u8..=1u8` not covered
1414
--> $DIR/const-pattern-irrefutable.rs:24:9
1515
|
16-
LL | let d = 4; //~ ERROR refutable pattern in local binding: `_` not covered
16+
LL | let d = 4; //~ ERROR refutable pattern in local binding: `0u8..=1u8` not covered
1717
| ^ interpreted as a constant pattern, not new variable
1818

1919
error: aborting due to 3 previous errors

src/test/ui/exhaustive_integer_patterns.rs

+3-10
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(exhaustive_integer_patterns)]
11+
#![feature(precise_pointer_size_matching)]
1212
#![feature(exclusive_range_pattern)]
13+
1314
#![deny(unreachable_patterns)]
1415

15-
use std::{char, usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128};
16+
use std::{char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128};
1617

1718
fn main() {
1819
let x: u8 = 0;
@@ -68,10 +69,6 @@ fn main() {
6869
'\u{E000}' ..= '\u{10_FFFF}' => {}
6970
}
7071

71-
match 0usize {
72-
0 ..= usize::MAX => {} // ok
73-
}
74-
7572
match 0u16 {
7673
0 ..= u16::MAX => {} // ok
7774
}
@@ -88,10 +85,6 @@ fn main() {
8885
0 ..= u128::MAX => {} // ok
8986
}
9087

91-
match 0isize {
92-
isize::MIN ..= isize::MAX => {} // ok
93-
}
94-
9588
match 0i8 {
9689
-128 ..= 127 => {} // ok
9790
}

src/test/ui/exhaustive_integer_patterns.stderr

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,83 @@
11
error: unreachable pattern
2-
--> $DIR/exhaustive_integer_patterns.rs:32:9
2+
--> $DIR/exhaustive_integer_patterns.rs:33:9
33
|
44
LL | 200 => {} //~ ERROR unreachable pattern
55
| ^^^
66
|
77
note: lint level defined here
8-
--> $DIR/exhaustive_integer_patterns.rs:13:9
8+
--> $DIR/exhaustive_integer_patterns.rs:14:9
99
|
1010
LL | #![deny(unreachable_patterns)]
1111
| ^^^^^^^^^^^^^^^^^^^^
1212

1313
error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered
14-
--> $DIR/exhaustive_integer_patterns.rs:37:11
14+
--> $DIR/exhaustive_integer_patterns.rs:38:11
1515
|
1616
LL | match x { //~ ERROR non-exhaustive patterns
1717
| ^ pattern `128u8..=255u8` not covered
1818

1919
error[E0004]: non-exhaustive patterns: `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
20-
--> $DIR/exhaustive_integer_patterns.rs:42:11
20+
--> $DIR/exhaustive_integer_patterns.rs:43:11
2121
|
2222
LL | match x { //~ ERROR non-exhaustive patterns
2323
| ^ patterns `11u8..=19u8`, `31u8..=34u8`, `36u8..=69u8` and 1 more not covered
2424

2525
error: unreachable pattern
26-
--> $DIR/exhaustive_integer_patterns.rs:53:9
26+
--> $DIR/exhaustive_integer_patterns.rs:54:9
2727
|
2828
LL | -2..=20 => {} //~ ERROR unreachable pattern
2929
| ^^^^^^^
3030

3131
error[E0004]: non-exhaustive patterns: `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
32-
--> $DIR/exhaustive_integer_patterns.rs:50:11
32+
--> $DIR/exhaustive_integer_patterns.rs:51:11
3333
|
3434
LL | match x { //~ ERROR non-exhaustive patterns
3535
| ^ patterns `-128i8..=-8i8`, `-6i8`, `121i8..=124i8` and 1 more not covered
3636

3737
error[E0004]: non-exhaustive patterns: `-128i8` not covered
38-
--> $DIR/exhaustive_integer_patterns.rs:99:11
38+
--> $DIR/exhaustive_integer_patterns.rs:92:11
3939
|
4040
LL | match 0i8 { //~ ERROR non-exhaustive patterns
4141
| ^^^ pattern `-128i8` not covered
4242

4343
error[E0004]: non-exhaustive patterns: `0i16` not covered
44-
--> $DIR/exhaustive_integer_patterns.rs:107:11
44+
--> $DIR/exhaustive_integer_patterns.rs:100:11
4545
|
4646
LL | match 0i16 { //~ ERROR non-exhaustive patterns
4747
| ^^^^ pattern `0i16` not covered
4848

4949
error[E0004]: non-exhaustive patterns: `128u8..=255u8` not covered
50-
--> $DIR/exhaustive_integer_patterns.rs:125:11
50+
--> $DIR/exhaustive_integer_patterns.rs:118:11
5151
|
5252
LL | match 0u8 { //~ ERROR non-exhaustive patterns
5353
| ^^^ pattern `128u8..=255u8` not covered
5454

5555
error[E0004]: non-exhaustive patterns: `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered
56-
--> $DIR/exhaustive_integer_patterns.rs:137:11
56+
--> $DIR/exhaustive_integer_patterns.rs:130:11
5757
|
5858
LL | match (0u8, Some(())) { //~ ERROR non-exhaustive patterns
5959
| ^^^^^^^^^^^^^^^ patterns `(0u8, Some(_))` and `(2u8..=255u8, Some(_))` not covered
6060

6161
error[E0004]: non-exhaustive patterns: `(126u8..=127u8, false)` not covered
62-
--> $DIR/exhaustive_integer_patterns.rs:142:11
62+
--> $DIR/exhaustive_integer_patterns.rs:135:11
6363
|
6464
LL | match (0u8, true) { //~ ERROR non-exhaustive patterns
6565
| ^^^^^^^^^^^ pattern `(126u8..=127u8, false)` not covered
6666

6767
error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211455u128` not covered
68-
--> $DIR/exhaustive_integer_patterns.rs:162:11
68+
--> $DIR/exhaustive_integer_patterns.rs:155:11
6969
|
7070
LL | match 0u128 { //~ ERROR non-exhaustive patterns
7171
| ^^^^^ pattern `340282366920938463463374607431768211455u128` not covered
7272

7373
error[E0004]: non-exhaustive patterns: `5u128..=340282366920938463463374607431768211455u128` not covered
74-
--> $DIR/exhaustive_integer_patterns.rs:166:11
74+
--> $DIR/exhaustive_integer_patterns.rs:159:11
7575
|
7676
LL | match 0u128 { //~ ERROR non-exhaustive patterns
7777
| ^^^^^ pattern `5u128..=340282366920938463463374607431768211455u128` not covered
7878

7979
error[E0004]: non-exhaustive patterns: `0u128..=3u128` not covered
80-
--> $DIR/exhaustive_integer_patterns.rs:170:11
80+
--> $DIR/exhaustive_integer_patterns.rs:163:11
8181
|
8282
LL | match 0u128 { //~ ERROR non-exhaustive patterns
8383
| ^^^^^ pattern `0u128..=3u128` not covered

0 commit comments

Comments
 (0)