about summary refs log tree commit diff
path: root/tests/ui/half-open-range-patterns
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/half-open-range-patterns')
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs10
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr14
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs11
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr21
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs11
-rw-r--r--tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr40
-rw-r--r--tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs7
-rw-r--r--tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr12
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs7
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr21
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs167
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr819
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs48
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs30
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr37
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs24
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr59
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs24
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr55
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs159
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs29
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs53
-rw-r--r--tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr159
-rw-r--r--tests/ui/half-open-range-patterns/pat-tuple-4.rs12
-rw-r--r--tests/ui/half-open-range-patterns/pat-tuple-5.rs9
-rw-r--r--tests/ui/half-open-range-patterns/pat-tuple-5.stderr14
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions0.rs31
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.rs29
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions1.stderr36
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.rs21
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions2.stderr17
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions3.rs23
-rw-r--r--tests/ui/half-open-range-patterns/range_pat_interactions3.stderr48
-rw-r--r--tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs16
-rw-r--r--tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.stderr9
-rw-r--r--tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs8
-rw-r--r--tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr30
-rw-r--r--tests/ui/half-open-range-patterns/slice_pattern_syntax_problem2.rs10
38 files changed, 2130 insertions, 0 deletions
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs
new file mode 100644
index 00000000000..b2e9ffb5772
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.rs
@@ -0,0 +1,10 @@
+#![feature(half_open_range_patterns_in_slices)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99.., _] => {},
+        //~^ ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
new file mode 100644
index 00000000000..095a1c6af37
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision.rs:6:13
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [_, 99.., _] => {},
+   |             ^^ expected struct `Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs
new file mode 100644
index 00000000000..20f4d8f882a
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.rs
@@ -0,0 +1,11 @@
+#![feature(half_open_range_patterns_in_slices)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99..] => {},
+        //~^ ERROR pattern requires 2 elements but array has 3
+        //~| ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
new file mode 100644
index 00000000000..2ea3205dcd4
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision2.stderr
@@ -0,0 +1,21 @@
+error[E0527]: pattern requires 2 elements but array has 3
+  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:6:9
+   |
+LL |         [_, 99..] => {},
+   |         ^^^^^^^^^ expected 3 elements
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision2.rs:6:13
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [_, 99..] => {},
+   |             ^^ expected struct `Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0527.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs
new file mode 100644
index 00000000000..14ca07d0a53
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.rs
@@ -0,0 +1,11 @@
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    match [5..4, 99..105, 43..44] {
+        [..9, 99..100, _] => {},
+        //~^ ERROR mismatched types
+        //~| ERROR mismatched types
+        //~| ERROR mismatched types
+        _ => {},
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
new file mode 100644
index 00000000000..bbdf0c83f62
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/exclusive_range_pattern_syntax_collision3.stderr
@@ -0,0 +1,40 @@
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |            ^ expected struct `Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |               ^^  --- this is of type `{integer}`
+   |               |
+   |               expected struct `Range`, found integer
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:19
+   |
+LL |     match [5..4, 99..105, 43..44] {
+   |           ----------------------- this expression has type `[std::ops::Range<{integer}>; 3]`
+LL |         [..9, 99..100, _] => {},
+   |               --  ^^^ expected struct `Range`, found integer
+   |               |
+   |               this is of type `{integer}`
+   |
+   = note: expected struct `std::ops::Range<{integer}>`
+                found type `{integer}`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs
new file mode 100644
index 00000000000..dac97347349
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.rs
@@ -0,0 +1,7 @@
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    let xs = [13, 1, 5, 2, 3, 1, 21, 8];
+    let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+    //~^ `X..` patterns in slices are experimental
+}
diff --git a/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr
new file mode 100644
index 00000000000..ee5b0e11c66
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/feature-gate-half-open-range-patterns-in-slices.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `X..` patterns in slices are experimental
+  --> $DIR/feature-gate-half-open-range-patterns-in-slices.rs:5:10
+   |
+LL |     let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+   |          ^^^^^^^
+   |
+   = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
+   = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
new file mode 100644
index 00000000000..17ea2b13f69
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs
@@ -0,0 +1,7 @@
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    let "a".. = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
+    let .."a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
+    let ..="a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
new file mode 100644
index 00000000000..f7c59a19619
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr
@@ -0,0 +1,21 @@
+error[E0029]: only `char` and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:4:9
+   |
+LL |     let "a".. = "a";
+   |         ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:5:11
+   |
+LL |     let .."a" = "a";
+   |           ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error[E0029]: only `char` and numeric types are allowed in range patterns
+  --> $DIR/half-open-range-pats-bad-types.rs:6:12
+   |
+LL |     let ..="a" = "a";
+   |            ^^^ this is of type `&'static str` but it should be `char` or numeric
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0029`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
new file mode 100644
index 00000000000..a2a4c62fa02
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.rs
@@ -0,0 +1,167 @@
+// Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges.
+
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+
+fn main() {}
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+fn floats() {
+    m!(0f32, f32::NEG_INFINITY..); //~ ERROR non-exhaustive patterns: `_` not covered
+    m!(0f32, ..f32::INFINITY); //~ ERROR non-exhaustive patterns: `_` not covered
+}
+
+fn khar() {
+    const ALMOST_MAX: char = '\u{10fffe}';
+    const ALMOST_MIN: char = '\u{1}';
+    const VAL: char = 'a';
+    const VAL_1: char = 'b';
+    const VAL_2: char = 'c';
+    m!('a', ..core::char::MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+    m!('a', ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+    m!('a', ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+    m!('a', ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+}
+
+mod unsigned {
+    fn u8() {
+        const ALMOST_MAX: u8 = u8::MAX - 1;
+        const ALMOST_MIN: u8 = u8::MIN + 1;
+        const VAL: u8 = 42;
+        const VAL_1: u8 = VAL + 1;
+        const VAL_2: u8 = VAL + 2;
+        m!(0, ..u8::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u16() {
+        const ALMOST_MAX: u16 = u16::MAX - 1;
+        const ALMOST_MIN: u16 = u16::MIN + 1;
+        const VAL: u16 = 42;
+        const VAL_1: u16 = VAL + 1;
+        const VAL_2: u16 = VAL + 2;
+        m!(0, ..u16::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u32() {
+        const ALMOST_MAX: u32 = u32::MAX - 1;
+        const ALMOST_MIN: u32 = u32::MIN + 1;
+        const VAL: u32 = 42;
+        const VAL_1: u32 = VAL + 1;
+        const VAL_2: u32 = VAL + 2;
+        m!(0, ..u32::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u64() {
+        const ALMOST_MAX: u64 = u64::MAX - 1;
+        const ALMOST_MIN: u64 = u64::MIN + 1;
+        const VAL: u64 = 42;
+        const VAL_1: u64 = VAL + 1;
+        const VAL_2: u64 = VAL + 2;
+        m!(0, ..u64::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn u128() {
+        const ALMOST_MAX: u128 = u128::MAX - 1;
+        const ALMOST_MIN: u128 = u128::MIN + 1;
+        const VAL: u128 = 42;
+        const VAL_1: u128 = VAL + 1;
+        const VAL_2: u128 = VAL + 2;
+        m!(0, ..u128::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+}
+
+mod signed {
+    fn i8() {
+        const ALMOST_MAX: i8 = i8::MAX - 1;
+        const ALMOST_MIN: i8 = i8::MIN + 1;
+        const VAL: i8 = 42;
+        const VAL_1: i8 = VAL + 1;
+        const VAL_2: i8 = VAL + 2;
+        m!(0, ..i8::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i16() {
+        const ALMOST_MAX: i16 = i16::MAX - 1;
+        const ALMOST_MIN: i16 = i16::MIN + 1;
+        const VAL: i16 = 42;
+        const VAL_1: i16 = VAL + 1;
+        const VAL_2: i16 = VAL + 2;
+        m!(0, ..i16::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i32() {
+        const ALMOST_MAX: i32 = i32::MAX - 1;
+        const ALMOST_MIN: i32 = i32::MIN + 1;
+        const VAL: i32 = 42;
+        const VAL_1: i32 = VAL + 1;
+        const VAL_2: i32 = VAL + 2;
+        m!(0, ..i32::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i64() {
+        const ALMOST_MAX: i64 = i64::MAX - 1;
+        const ALMOST_MIN: i64 = i64::MIN + 1;
+        const VAL: i64 = 42;
+        const VAL_1: i64 = VAL + 1;
+        const VAL_2: i64 = VAL + 2;
+        m!(0, ..i64::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+    fn i128() {
+        const ALMOST_MAX: i128 = i128::MAX - 1;
+        const ALMOST_MIN: i128 = i128::MIN + 1;
+        const VAL: i128 = 42;
+        const VAL_1: i128 = VAL + 1;
+        const VAL_2: i128 = VAL + 2;
+        m!(0, ..i128::MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ALMOST_MIN..); //~ ERROR non-exhaustive patterns
+        m!(0, ..=ALMOST_MAX); //~ ERROR non-exhaustive patterns
+        m!(0, ..=VAL | VAL_2..); //~ ERROR non-exhaustive patterns
+        m!(0, ..VAL_1 | VAL_2..); //~ ERROR non-exhaustive patterns
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
new file mode 100644
index 00000000000..6b20a820b73
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr
@@ -0,0 +1,819 @@
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8
+   |
+LL |     m!(0f32, f32::NEG_INFINITY..);
+   |        ^^^^ pattern `_` not covered
+   |
+   = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, _ => todo!() }
+   |                                ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `_` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8
+   |
+LL |     m!(0f32, ..f32::INFINITY);
+   |        ^^^^ pattern `_` not covered
+   |
+   = note: the matched value is of type `f32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, _ => todo!() }
+   |                                ++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8
+   |
+LL |     m!('a', ..core::char::MAX);
+   |        ^^^ pattern `'\u{10ffff}'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
+   |                                +++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
+   |
+LL |     m!('a', ..ALMOST_MAX);
+   |        ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, '\u{10fffe}'..='\u{10ffff}' => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'\0'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
+   |
+LL |     m!('a', ALMOST_MIN..);
+   |        ^^^ pattern `'\0'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, '\0' => todo!() }
+   |                                +++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
+   |
+LL |     m!('a', ..=ALMOST_MAX);
+   |        ^^^ pattern `'\u{10ffff}'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
+   |                                +++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'b'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
+   |
+LL |     m!('a', ..=VAL | VAL_2..);
+   |        ^^^ pattern `'b'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 'b' => todo!() }
+   |                                ++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `'b'` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
+   |
+LL |     m!('a', ..VAL_1 | VAL_2..);
+   |        ^^^ pattern `'b'` not covered
+   |
+   = note: the matched value is of type `char`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 'b' => todo!() }
+   |                                ++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12
+   |
+LL |         m!(0, ..u8::MAX);
+   |            ^ pattern `u8::MAX` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u8::MAX => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `254_u8..=u8::MAX` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 254_u8..=u8::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0_u8` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 0_u8 => todo!() }
+   |                                +++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `u8::MAX` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u8::MAX => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_u8` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u8 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_u8` not covered
+   |
+   = note: the matched value is of type `u8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u8 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12
+   |
+LL |         m!(0, ..u16::MAX);
+   |            ^ pattern `u16::MAX` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u16::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `65534_u16..=u16::MAX` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 65534_u16..=u16::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0_u16` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 0_u16 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `u16::MAX` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u16::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_u16` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u16 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_u16` not covered
+   |
+   = note: the matched value is of type `u16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u16 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12
+   |
+LL |         m!(0, ..u32::MAX);
+   |            ^ pattern `u32::MAX` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u32::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `4294967294_u32..=u32::MAX` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 4294967294_u32..=u32::MAX => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0_u32` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 0_u32 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `u32::MAX` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u32::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_u32` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u32 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_u32` not covered
+   |
+   = note: the matched value is of type `u32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u32 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12
+   |
+LL |         m!(0, ..u64::MAX);
+   |            ^ pattern `u64::MAX` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u64::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 18446744073709551614_u64..=u64::MAX => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0_u64` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 0_u64 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `u64::MAX` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u64::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_u64` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u64 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_u64` not covered
+   |
+   = note: the matched value is of type `u64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u64 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12
+   |
+LL |         m!(0, ..u128::MAX);
+   |            ^ pattern `u128::MAX` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
+   |                                ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u128..=u128::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `0_u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `0_u128` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 0_u128 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `u128::MAX` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, u128::MAX => todo!() }
+   |                                ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_u128` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u128 => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_u128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_u128` not covered
+   |
+   = note: the matched value is of type `u128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_u128 => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12
+   |
+LL |         m!(0, ..i8::MAX);
+   |            ^ pattern `i8::MAX` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i8::MAX => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `126_i8..=i8::MAX` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 126_i8..=i8::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `i8::MIN` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i8::MIN => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `i8::MAX` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i8::MAX => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_i8` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i8 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i8` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_i8` not covered
+   |
+   = note: the matched value is of type `i8`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i8 => todo!() }
+   |                                ++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12
+   |
+LL |         m!(0, ..i16::MAX);
+   |            ^ pattern `i16::MAX` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i16::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `32766_i16..=i16::MAX` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 32766_i16..=i16::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `i16::MIN` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i16::MIN => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `i16::MAX` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i16::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_i16` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i16 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i16` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_i16` not covered
+   |
+   = note: the matched value is of type `i16`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i16 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12
+   |
+LL |         m!(0, ..i32::MAX);
+   |            ^ pattern `i32::MAX` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i32::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `2147483646_i32..=i32::MAX` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 2147483646_i32..=i32::MAX => todo!() }
+   |                                ++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `i32::MIN` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i32::MIN => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `i32::MAX` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i32::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_i32` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i32 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i32` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_i32` not covered
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i32 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12
+   |
+LL |         m!(0, ..i64::MAX);
+   |            ^ pattern `i64::MAX` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i64::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 9223372036854775806_i64..=i64::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `i64::MIN` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i64::MIN => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `i64::MAX` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i64::MAX => todo!() }
+   |                                +++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_i64` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i64 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i64` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_i64` not covered
+   |
+   = note: the matched value is of type `i64`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i64 => todo!() }
+   |                                +++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12
+   |
+LL |         m!(0, ..i128::MAX);
+   |            ^ pattern `i128::MAX` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i128::MAX => todo!() }
+   |                                ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
+   |
+LL |         m!(0, ..ALMOST_MAX);
+   |            ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i128..=i128::MAX => todo!() }
+   |                                +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
+   |
+LL |         m!(0, ALMOST_MIN..);
+   |            ^ pattern `i128::MIN` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i128::MIN => todo!() }
+   |                                ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
+   |
+LL |         m!(0, ..=ALMOST_MAX);
+   |            ^ pattern `i128::MAX` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, i128::MAX => todo!() }
+   |                                ++++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
+   |
+LL |         m!(0, ..=VAL | VAL_2..);
+   |            ^ pattern `43_i128` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i128 => todo!() }
+   |                                ++++++++++++++++++++
+
+error[E0004]: non-exhaustive patterns: `43_i128` not covered
+  --> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
+   |
+LL |         m!(0, ..VAL_1 | VAL_2..);
+   |            ^ pattern `43_i128` not covered
+   |
+   = note: the matched value is of type `i128`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL |         match $s { $($t)+ => {}, 43_i128 => todo!() }
+   |                                ++++++++++++++++++++
+
+error: aborting due to 68 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs
new file mode 100644
index 00000000000..4b7eee134e4
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-exhaustive-pass.rs
@@ -0,0 +1,48 @@
+// check-pass
+
+// Test various exhaustive matches for `X..`, `..=X` and `..X` ranges.
+
+#![feature(exclusive_range_pattern)]
+
+fn main() {}
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+macro_rules! test_int {
+    ($s:expr, $min:path, $max:path) => {
+        m!($s, $min..);
+        m!($s, $min..5 | 5..);
+        m!($s, ..5 | 5..);
+        m!($s, ..=4 | 5..);
+        m!($s, ..=$max);
+        m!($s, ..$max | $max);
+        m!(($s, true), (..5, true) | (5.., true) | ($min.., false));
+    }
+}
+
+fn unsigned_int() {
+    test_int!(0u8, u8::MIN, u8::MAX);
+    test_int!(0u16, u16::MIN, u16::MAX);
+    test_int!(0u32, u32::MIN, u32::MAX);
+    test_int!(0u64, u64::MIN, u64::MAX);
+    test_int!(0u128, u128::MIN, u128::MAX);
+}
+
+fn signed_int() {
+    test_int!(0i8, i8::MIN, i8::MAX);
+    test_int!(0i16, i16::MIN, i16::MAX);
+    test_int!(0i32, i32::MIN, i32::MAX);
+    test_int!(0i64, i64::MIN, i64::MAX);
+    test_int!(0i128, i128::MIN, i128::MAX);
+}
+
+fn khar() {
+    m!('a', ..=core::char::MAX);
+    m!('a', '\u{0}'..);
+    m!('a', ..='\u{D7FF}' | '\u{E000}'..);
+    m!('a', ..'\u{D7FF}' | '\u{D7FF}' | '\u{E000}'..);
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
new file mode 100644
index 00000000000..526a797e9d6
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
@@ -0,0 +1,30 @@
+// Test that `...X` range-to patterns are syntactically invalid.
+//
+// See https://github.com/rust-lang/rust/pull/67258#issuecomment-565656155
+// for the reason why. To summarize, we might want to introduce `...expr` as
+// an expression form for splatting (or "untupling") in an expression context.
+// While there is no syntactic ambiguity with `...X` in a pattern context,
+// there's a potential confusion factor here, and we would prefer to keep patterns
+// and expressions in-sync. As such, we do not allow `...X` in patterns either.
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match scrutinee {
+        ...X => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0 => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...'a' => {} //~ ERROR range-to patterns with `...` are not allowed
+        ...0.0f32 => {} //~ ERROR range-to patterns with `...` are not allowed
+    }
+}
+
+fn syntax2() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let ...$e; //~ ERROR range-to patterns with `...` are not allowed
+        }
+    }
+
+    mac!(0);
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
new file mode 100644
index 00000000000..ddffeaf9780
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.stderr
@@ -0,0 +1,37 @@
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:15:9
+   |
+LL |         ...X => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:16:9
+   |
+LL |         ...0 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:17:9
+   |
+LL |         ...'a' => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:18:9
+   |
+LL |         ...0.0f32 => {}
+   |         ^^^ help: use `..=` instead
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs:25:17
+   |
+LL |             let ...$e;
+   |                 ^^^ help: use `..=` instead
+...
+LL |     mac!(0);
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
new file mode 100644
index 00000000000..6567c8cc67c
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
@@ -0,0 +1,24 @@
+// Test `X...` and `X..=` range patterns not being allowed syntactically.
+// FIXME(Centril): perhaps these should be semantic restrictions.
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn foo() {
+    if let 0... = 1 {} //~ ERROR inclusive range with no end
+    if let 0..= = 1 {} //~ ERROR inclusive range with no end
+    const X: u8 = 0;
+    if let X... = 1 {} //~ ERROR inclusive range with no end
+    if let X..= = 1 {} //~ ERROR inclusive range with no end
+}
+
+fn bar() {
+    macro_rules! mac {
+        ($e:expr) => {
+            let $e...; //~ ERROR inclusive range with no end
+            let $e..=; //~ ERROR inclusive range with no end
+        }
+    }
+
+    mac!(0);
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
new file mode 100644
index 00000000000..3ad84b0ef26
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.stderr
@@ -0,0 +1,59 @@
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:8:13
+   |
+LL |     if let 0... = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:9:13
+   |
+LL |     if let 0..= = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:11:13
+   |
+LL |     if let X... = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:12:13
+   |
+LL |     if let X..= = 1 {}
+   |             ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:18:19
+   |
+LL |             let $e...;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     ------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-inclusive-no-end.rs:19:19
+   |
+LL |             let $e..=;
+   |                   ^^^ help: use `..` instead
+...
+LL |     mac!(0);
+   |     ------- in this macro invocation
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
new file mode 100644
index 00000000000..2d63fe07856
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
@@ -0,0 +1,24 @@
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match &0 {
+        &0.. | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &0..= | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~| ERROR inclusive range with no end
+        &0... | _ => {}
+        //~^ ERROR inclusive range with no end
+    }
+
+    match &0 {
+        &..0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &..=0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        &...0 | _ => {}
+        //~^ ERROR the range pattern here has ambiguous interpretation
+        //~| ERROR range-to patterns with `...` are not allowed
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
new file mode 100644
index 00000000000..111e8179962
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.stderr
@@ -0,0 +1,55 @@
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:6:10
+   |
+LL |         &0.. | _ => {}
+   |          ^^^ help: add parentheses to clarify the precedence: `(0..)`
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:11
+   |
+LL |         &0..= | _ => {}
+   |           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:8:10
+   |
+LL |         &0..= | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(0..=)`
+
+error[E0586]: inclusive range with no end
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:11:11
+   |
+LL |         &0... | _ => {}
+   |           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:16:10
+   |
+LL |         &..0 | _ => {}
+   |          ^^^ help: add parentheses to clarify the precedence: `(..0)`
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:18:10
+   |
+LL |         &..=0 | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+
+error: range-to patterns with `...` are not allowed
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^ help: use `..=` instead
+
+error: the range pattern here has ambiguous interpretation
+  --> $DIR/half-open-range-pats-ref-ambiguous-interp.rs:20:10
+   |
+LL |         &...0 | _ => {}
+   |          ^^^^ help: add parentheses to clarify the precedence: `(..=0)`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
new file mode 100644
index 00000000000..6c6ba93196b
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs
@@ -0,0 +1,159 @@
+// run-pass
+
+// Test half-open range patterns against their expression equivalents
+// via `.contains(...)` and make sure the dynamic semantics match.
+
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+#![allow(unreachable_patterns)]
+
+macro_rules! yes {
+    ($scrutinee:expr, $($t:tt)+) => {
+        {
+            let m = match $scrutinee { $($t)+ => true, _ => false, };
+            let c = ($($t)+).contains(&$scrutinee);
+            assert_eq!(m, c);
+            m
+        }
+    }
+}
+
+fn range_to_inclusive() {
+    // `..=X` (`RangeToInclusive`-equivalent):
+    //---------------------------------------
+
+    // u8; `..=X`
+    assert!(yes!(u8::MIN, ..=u8::MIN));
+    assert!(yes!(u8::MIN, ..=5));
+    assert!(yes!(5u8, ..=5));
+    assert!(!yes!(6u8, ..=5));
+
+    // i16; `..=X`
+    assert!(yes!(i16::MIN, ..=i16::MIN));
+    assert!(yes!(i16::MIN, ..=0));
+    assert!(yes!(i16::MIN, ..=-5));
+    assert!(yes!(-5, ..=-5));
+    assert!(!yes!(-4, ..=-5));
+
+    // char; `..=X`
+    assert!(yes!('\u{0}', ..='\u{0}'));
+    assert!(yes!('\u{0}', ..='a'));
+    assert!(yes!('a', ..='a'));
+    assert!(!yes!('b', ..='a'));
+
+    // f32; `..=X`
+    assert!(yes!(f32::NEG_INFINITY, ..=f32::NEG_INFINITY));
+    assert!(yes!(f32::NEG_INFINITY, ..=1.0f32));
+    assert!(yes!(1.5f32, ..=1.5f32));
+    assert!(!yes!(1.6f32, ..=-1.5f32));
+
+    // f64; `..=X`
+    assert!(yes!(f64::NEG_INFINITY, ..=f64::NEG_INFINITY));
+    assert!(yes!(f64::NEG_INFINITY, ..=1.0f64));
+    assert!(yes!(1.5f64, ..=1.5f64));
+    assert!(!yes!(1.6f64, ..=-1.5f64));
+}
+
+fn range_to() {
+    // `..X` (`RangeTo`-equivalent):
+    //-----------------------------
+
+    // u8; `..X`
+    assert!(yes!(0u8, ..1));
+    assert!(yes!(0u8, ..5));
+    assert!(!yes!(5u8, ..5));
+    assert!(!yes!(6u8, ..5));
+
+    // u8; `..X`
+    const NU8: u8 = u8::MIN + 1;
+    assert!(yes!(u8::MIN, ..NU8));
+    assert!(yes!(0u8, ..5));
+    assert!(!yes!(5u8, ..5));
+    assert!(!yes!(6u8, ..5));
+
+    // i16; `..X`
+    const NI16: i16 = i16::MIN + 1;
+    assert!(yes!(i16::MIN, ..NI16));
+    assert!(yes!(i16::MIN, ..5));
+    assert!(yes!(-6, ..-5));
+    assert!(!yes!(-5, ..-5));
+
+    // char; `..X`
+    assert!(yes!('\u{0}', ..'\u{1}'));
+    assert!(yes!('\u{0}', ..'a'));
+    assert!(yes!('a', ..'b'));
+    assert!(!yes!('a', ..'a'));
+    assert!(!yes!('b', ..'a'));
+
+    // f32; `..X`
+    assert!(yes!(f32::NEG_INFINITY, ..1.0f32));
+    assert!(!yes!(1.5f32, ..1.5f32));
+    const E32: f32 = 1.5f32 + f32::EPSILON;
+    assert!(yes!(1.5f32, ..E32));
+    assert!(!yes!(1.6f32, ..1.5f32));
+
+    // f64; `..X`
+    assert!(yes!(f64::NEG_INFINITY, ..1.0f64));
+    assert!(!yes!(1.5f64, ..1.5f64));
+    const E64: f64 = 1.5f64 + f64::EPSILON;
+    assert!(yes!(1.5f64, ..E64));
+    assert!(!yes!(1.6f64, ..1.5f64));
+}
+
+fn range_from() {
+    // `X..` (`RangeFrom`-equivalent):
+    //--------------------------------
+
+    // u8; `X..`
+    assert!(yes!(u8::MIN, u8::MIN..));
+    assert!(yes!(u8::MAX, u8::MIN..));
+    assert!(!yes!(u8::MIN, 1..));
+    assert!(!yes!(4, 5..));
+    assert!(yes!(5, 5..));
+    assert!(yes!(6, 5..));
+    assert!(yes!(u8::MAX, u8::MAX..));
+
+    // i16; `X..`
+    assert!(yes!(i16::MIN, i16::MIN..));
+    assert!(yes!(i16::MAX, i16::MIN..));
+    const NI16: i16 = i16::MIN + 1;
+    assert!(!yes!(i16::MIN, NI16..));
+    assert!(!yes!(-4, 5..));
+    assert!(yes!(-4, -4..));
+    assert!(yes!(-3, -4..));
+    assert!(yes!(i16::MAX, i16::MAX..));
+
+    // char; `X..`
+    assert!(yes!('\u{0}', '\u{0}'..));
+    assert!(yes!(core::char::MAX, '\u{0}'..));
+    assert!(yes!('a', 'a'..));
+    assert!(yes!('b', 'a'..));
+    assert!(!yes!('a', 'b'..));
+    assert!(yes!(core::char::MAX, core::char::MAX..));
+
+    // f32; `X..`
+    assert!(yes!(f32::NEG_INFINITY, f32::NEG_INFINITY..));
+    assert!(yes!(f32::INFINITY, f32::NEG_INFINITY..));
+    assert!(!yes!(f32::NEG_INFINITY, 1.0f32..));
+    assert!(yes!(f32::INFINITY, 1.0f32..));
+    assert!(!yes!(1.0f32 - f32::EPSILON, 1.0f32..));
+    assert!(yes!(1.0f32, 1.0f32..));
+    assert!(yes!(f32::INFINITY, 1.0f32..));
+    assert!(yes!(f32::INFINITY, f32::INFINITY..));
+
+    // f64; `X..`
+    assert!(yes!(f64::NEG_INFINITY, f64::NEG_INFINITY..));
+    assert!(yes!(f64::INFINITY, f64::NEG_INFINITY..));
+    assert!(!yes!(f64::NEG_INFINITY, 1.0f64..));
+    assert!(yes!(f64::INFINITY, 1.0f64..));
+    assert!(!yes!(1.0f64 - f64::EPSILON, 1.0f64..));
+    assert!(yes!(1.0f64, 1.0f64..));
+    assert!(yes!(f64::INFINITY, 1.0f64..));
+    assert!(yes!(f64::INFINITY, f64::INFINITY..));
+}
+
+fn main() {
+    range_to_inclusive();
+    range_to();
+    range_from();
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
new file mode 100644
index 00000000000..9a73e89063f
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+// Test the parsing of half-open ranges.
+
+#![feature(exclusive_range_pattern)]
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn syntax() {
+    match scrutinee {
+        X.. | 0.. | 'a'.. | 0.0f32.. => {}
+        ..=X | ..X => {}
+        ..=0 | ..0 => {}
+        ..='a' | ..'a' => {}
+        ..=0.0f32 | ..0.0f32 => {}
+    }
+}
+
+fn syntax2() {
+    macro_rules! mac {
+        ($e:expr) => {
+            match 0u8 { ..$e => {}, _ => {} }
+            match 0u8 { ..=$e => {}, _ => {} }
+            match 0u8 { $e.. => {}, _ => {} }
+        }
+    }
+    mac!(42u8);
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
new file mode 100644
index 00000000000..f55566602db
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs
@@ -0,0 +1,53 @@
+#![feature(exclusive_range_pattern)]
+#![allow(illegal_floating_point_literal_pattern)]
+
+macro_rules! m {
+    ($s:expr, $($t:tt)+) => {
+        match $s { $($t)+ => {} }
+    }
+}
+
+fn main() {
+    m!(0, ..u8::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..u16::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..u32::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..u64::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..u128::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!(0, ..i8::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..i16::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..i32::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..i64::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0, ..i128::MIN);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!(0f32, ..f32::NEG_INFINITY);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+    m!(0f64, ..f64::NEG_INFINITY);
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+
+    m!('a', ..'\u{0}');
+    //~^ ERROR lower range bound must be less than upper
+    //~| ERROR lower range bound must be less than upper
+}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
new file mode 100644
index 00000000000..56b224a8542
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr
@@ -0,0 +1,159 @@
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11
+   |
+LL |     m!(0, ..u8::MIN);
+   |           ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
+   |
+LL |     m!(0, ..u16::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
+   |
+LL |     m!(0, ..u32::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11
+   |
+LL |     m!(0, ..u64::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
+   |
+LL |     m!(0, ..u128::MIN);
+   |           ^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
+   |
+LL |     m!(0, ..i8::MIN);
+   |           ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
+   |
+LL |     m!(0, ..i16::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11
+   |
+LL |     m!(0, ..i32::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11
+   |
+LL |     m!(0, ..i64::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11
+   |
+LL |     m!(0, ..i128::MIN);
+   |           ^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14
+   |
+LL |     m!(0f32, ..f32::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14
+   |
+LL |     m!(0f64, ..f64::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13
+   |
+LL |     m!('a', ..'\u{0}');
+   |             ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11
+   |
+LL |     m!(0, ..u8::MIN);
+   |           ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
+   |
+LL |     m!(0, ..u16::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
+   |
+LL |     m!(0, ..u32::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:20:11
+   |
+LL |     m!(0, ..u64::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
+   |
+LL |     m!(0, ..u128::MIN);
+   |           ^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
+   |
+LL |     m!(0, ..i8::MIN);
+   |           ^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
+   |
+LL |     m!(0, ..i16::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:33:11
+   |
+LL |     m!(0, ..i32::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:11
+   |
+LL |     m!(0, ..i64::MIN);
+   |           ^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:39:11
+   |
+LL |     m!(0, ..i128::MIN);
+   |           ^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:43:14
+   |
+LL |     m!(0f32, ..f32::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:46:14
+   |
+LL |     m!(0f64, ..f64::NEG_INFINITY);
+   |              ^^^^^^^^^^^^^^^^^^^
+
+error[E0579]: lower range bound must be less than upper
+  --> $DIR/half-open-range-pats-thir-lower-empty.rs:50:13
+   |
+LL |     m!('a', ..'\u{0}');
+   |             ^^^^^^^^^
+
+error: aborting due to 26 previous errors
+
+For more information about this error, try `rustc --explain E0579`.
diff --git a/tests/ui/half-open-range-patterns/pat-tuple-4.rs b/tests/ui/half-open-range-patterns/pat-tuple-4.rs
new file mode 100644
index 00000000000..11c4ab9c5fc
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/pat-tuple-4.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    const PAT: u8 = 1;
+
+    match 0 {
+        (.. PAT) => {}
+        _ => {}
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/pat-tuple-5.rs b/tests/ui/half-open-range-patterns/pat-tuple-5.rs
new file mode 100644
index 00000000000..995ef03c83e
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/pat-tuple-5.rs
@@ -0,0 +1,9 @@
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    const PAT: u8 = 1;
+
+    match (0, 1) {
+        (PAT ..) => {} //~ ERROR mismatched types
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/pat-tuple-5.stderr b/tests/ui/half-open-range-patterns/pat-tuple-5.stderr
new file mode 100644
index 00000000000..c608426382d
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/pat-tuple-5.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/pat-tuple-5.rs:7:10
+   |
+LL |     match (0, 1) {
+   |           ------ this expression has type `({integer}, {integer})`
+LL |         (PAT ..) => {}
+   |          ^^^ expected tuple, found `u8`
+   |
+   = note: expected tuple `({integer}, {integer})`
+               found type `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions0.rs b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs
new file mode 100644
index 00000000000..acb7feac132
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions0.rs
@@ -0,0 +1,31 @@
+// run-pass
+#![allow(incomplete_features)]
+#![feature(exclusive_range_pattern)]
+#![feature(inline_const_pat)]
+
+fn main() {
+    let mut if_lettable = vec![];
+    let mut first_or = vec![];
+    let mut or_two = vec![];
+    let mut range_from = vec![];
+    let mut bottom = vec![];
+
+    for x in -9 + 1..=(9 - 2) {
+        if let -1..=0 | 2..3 | 4 = x {
+            if_lettable.push(x)
+        }
+        match x {
+            1 | -3..0 => first_or.push(x),
+            y @ (0..5 | 6) => or_two.push(y),
+            y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            y @ -5.. => range_from.push(y),
+            y @ ..-7 => assert_eq!(y, -8),
+            y => bottom.push(y),
+        }
+    }
+    assert_eq!(if_lettable, [-1, 0, 2, 4]);
+    assert_eq!(first_or, [-3, -2, -1, 1]);
+    assert_eq!(or_two, [0, 2, 3, 4, 6]);
+    assert_eq!(range_from, [-5, -4, 7]);
+    assert_eq!(bottom, [-7, -6]);
+}
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.rs b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
new file mode 100644
index 00000000000..55353999b67
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.rs
@@ -0,0 +1,29 @@
+fn main() {
+    let mut if_lettable = Vec::<i32>::new();
+    let mut first_or = Vec::<i32>::new();
+    let mut or_two = Vec::<i32>::new();
+    let mut range_from = Vec::<i32>::new();
+    let mut bottom = Vec::<i32>::new();
+    let mut errors_only = Vec::<i32>::new();
+
+    for x in -9 + 1..=(9 - 2) {
+        if let n @ 2..3|4 = x {
+            //~^ error: variable `n` is not bound in all patterns
+            //~| exclusive range pattern syntax is experimental
+            errors_only.push(x);
+        } else if let 2..3 | 4 = x {
+            //~^ exclusive range pattern syntax is experimental
+            if_lettable.push(x);
+        }
+        match x as i32 {
+            0..5+1 => errors_only.push(x),
+            //~^ error: expected one of `=>`, `if`, or `|`, found `+`
+            1 | -3..0 => first_or.push(x),
+            y @ (0..5 | 6) => or_two.push(y),
+            y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            y @ -5.. => range_from.push(y),
+            y @ ..-7 => assert_eq!(y, -8),
+            y => bottom.push(y),
+        }
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
new file mode 100644
index 00000000000..19ebcaf0f36
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions1.stderr
@@ -0,0 +1,36 @@
+error: expected one of `=>`, `if`, or `|`, found `+`
+  --> $DIR/range_pat_interactions1.rs:19:17
+   |
+LL |             0..5+1 => errors_only.push(x),
+   |                 ^ expected one of `=>`, `if`, or `|`
+
+error[E0408]: variable `n` is not bound in all patterns
+  --> $DIR/range_pat_interactions1.rs:10:25
+   |
+LL |         if let n @ 2..3|4 = x {
+   |                -        ^ pattern doesn't bind `n`
+   |                |
+   |                variable not in all patterns
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:10:20
+   |
+LL |         if let n @ 2..3|4 = x {
+   |                    ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions1.rs:14:23
+   |
+LL |         } else if let 2..3 | 4 = x {
+   |                       ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0408, E0658.
+For more information about an error, try `rustc --explain E0408`.
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.rs b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
new file mode 100644
index 00000000000..4615ebd688a
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.rs
@@ -0,0 +1,21 @@
+fn main() {
+    let mut first_or = Vec::<i32>::new();
+    let mut or_two = Vec::<i32>::new();
+    let mut range_from = Vec::<i32>::new();
+    let mut bottom = Vec::<i32>::new();
+    let mut errors_only = Vec::<i32>::new();
+
+    for x in -9 + 1..=(9 - 2) {
+        match x as i32 {
+            0..=(5+1) => errors_only.push(x),
+            //~^ error: inclusive range with no end
+            //~| error: expected one of `=>`, `if`, or `|`, found `(`
+            1 | -3..0 => first_or.push(x),
+            y @ (0..5 | 6) => or_two.push(y),
+            y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            y @ -5.. => range_from.push(y),
+            y @ ..-7 => assert_eq!(y, -8),
+            y => bottom.push(y),
+        }
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
new file mode 100644
index 00000000000..13a5542a474
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions2.stderr
@@ -0,0 +1,17 @@
+error[E0586]: inclusive range with no end
+  --> $DIR/range_pat_interactions2.rs:10:14
+   |
+LL |             0..=(5+1) => errors_only.push(x),
+   |              ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: expected one of `=>`, `if`, or `|`, found `(`
+  --> $DIR/range_pat_interactions2.rs:10:17
+   |
+LL |             0..=(5+1) => errors_only.push(x),
+   |                 ^ expected one of `=>`, `if`, or `|`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions3.rs b/tests/ui/half-open-range-patterns/range_pat_interactions3.rs
new file mode 100644
index 00000000000..446ed45f9c6
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions3.rs
@@ -0,0 +1,23 @@
+fn main() {
+    let mut first_or = Vec::<i32>::new();
+    let mut or_two = Vec::<i32>::new();
+    let mut range_from = Vec::<i32>::new();
+    let mut bottom = Vec::<i32>::new();
+
+    for x in -9 + 1..=(9 - 2) {
+        match x as i32 {
+            8.. => bottom.push(x),
+            1 | -3..0 => first_or.push(x),
+            //~^ exclusive range pattern syntax is experimental
+            y @ (0..5 | 6) => or_two.push(y),
+            //~^ exclusive range pattern syntax is experimental
+            y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+            //~^ inline-const in pattern position is experimental
+            //~| exclusive range pattern syntax is experimental
+            y @ -5.. => range_from.push(y),
+            y @ ..-7 => assert_eq!(y, -8),
+            //~^ exclusive range pattern syntax is experimental
+            y => bottom.push(y),
+        }
+    }
+}
diff --git a/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr b/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr
new file mode 100644
index 00000000000..f7fda67758f
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/range_pat_interactions3.stderr
@@ -0,0 +1,48 @@
+error[E0658]: inline-const in pattern position is experimental
+  --> $DIR/range_pat_interactions3.rs:14:20
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                    ^^^^^
+   |
+   = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
+   = help: add `#![feature(inline_const_pat)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions3.rs:10:17
+   |
+LL |             1 | -3..0 => first_or.push(x),
+   |                 ^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions3.rs:12:18
+   |
+LL |             y @ (0..5 | 6) => or_two.push(y),
+   |                  ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions3.rs:14:17
+   |
+LL |             y @ 0..const { 5 + 1 } => assert_eq!(y, 5),
+   |                 ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/range_pat_interactions3.rs:18:17
+   |
+LL |             y @ ..-7 => assert_eq!(y, -8),
+   |                 ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs
new file mode 100644
index 00000000000..d54cbfbf4bb
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.rs
@@ -0,0 +1,16 @@
+#![feature(half_open_range_patterns_in_slices)]
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    let xs = [13, 1, 5, 2, 3, 1, 21, 8];
+    let [a, b, c, rest @ ..] = xs;
+    // Consider the following example:
+    assert!(a == 13 && b == 1 && c == 5 && rest.len() == 5);
+
+    // What if we wanted to pull this apart without individually binding a, b, and c?
+    let [first_three @ ..3, rest @ 2..] = xs;
+    //~^ pattern requires 2 elements but array has 8
+    // This is somewhat unintuitive and makes slice patterns exceedingly verbose.
+    // We want to stabilize half-open RangeFrom (`X..`) patterns
+    // but without banning us from using them for a more efficient slice pattern syntax.
+}
diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.stderr b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.stderr
new file mode 100644
index 00000000000..ec3472a5036
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem0.stderr
@@ -0,0 +1,9 @@
+error[E0527]: pattern requires 2 elements but array has 8
+  --> $DIR/slice_pattern_syntax_problem0.rs:11:9
+   |
+LL |     let [first_three @ ..3, rest @ 2..] = xs;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 8 elements
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0527`.
diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs
new file mode 100644
index 00000000000..c37af75b8fb
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.rs
@@ -0,0 +1,8 @@
+// Instead of allowing the previous case, maintain the feature gate for slice patterns for now.
+fn main() {
+    let xs = [13, 1, 5, 2, 3, 1, 21, 8];
+    let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+    //~^ `X..` patterns in slices are experimental
+    //~| exclusive range pattern syntax is experimental
+    //~| exclusive range pattern syntax is experimental
+}
diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr
new file mode 100644
index 00000000000..3bca554b1e5
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem1.stderr
@@ -0,0 +1,30 @@
+error[E0658]: `X..` patterns in slices are experimental
+  --> $DIR/slice_pattern_syntax_problem1.rs:4:10
+   |
+LL |     let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+   |          ^^^^^^^
+   |
+   = note: see issue #67264 <https://github.com/rust-lang/rust/issues/67264> for more information
+   = help: add `#![feature(half_open_range_patterns_in_slices)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/slice_pattern_syntax_problem1.rs:4:23
+   |
+LL |     let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+   |                       ^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error[E0658]: exclusive range pattern syntax is experimental
+  --> $DIR/slice_pattern_syntax_problem1.rs:4:32
+   |
+LL |     let [a @ 3.., b @ ..3, c @ 4..6, ..] = xs;
+   |                                ^^^^
+   |
+   = note: see issue #37854 <https://github.com/rust-lang/rust/issues/37854> for more information
+   = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem2.rs b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem2.rs
new file mode 100644
index 00000000000..6e7df309491
--- /dev/null
+++ b/tests/ui/half-open-range-patterns/slice_pattern_syntax_problem2.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+fn main() {
+    let xs = [13, 1, 5, 2, 3, 1, 21, 8];
+    if let [3..=14, ..] = xs {
+        /* this variant must pass for now, unfortunately.
+         * This test is included here to help inform a future plan for these.
+         */
+    };
+}