Skip to content

Commit 70deb9a

Browse files
committed
Disallow arm bodies on never patterns
1 parent 06a8ed1 commit 70deb9a

File tree

8 files changed

+75
-26
lines changed

8 files changed

+75
-26
lines changed

compiler/rustc_ast_lowering/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ ast_lowering_misplaced_impl_trait =
108108
ast_lowering_misplaced_relax_trait_bound =
109109
`?Trait` bounds are only permitted at the point where a type parameter is declared
110110
111+
ast_lowering_never_pattern_with_body =
112+
a never pattern is always unreachable
113+
.label = this will never be executed
114+
.suggestion = remove this expression
115+
111116
ast_lowering_never_pattern_with_guard =
112117
a guard on a never pattern will never be run
113118
.suggestion = remove this guard

compiler/rustc_ast_lowering/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,15 @@ pub struct MatchArmWithNoBody {
349349
pub suggestion: Span,
350350
}
351351

352+
#[derive(Diagnostic)]
353+
#[diag(ast_lowering_never_pattern_with_body)]
354+
pub struct NeverPatternWithBody {
355+
#[primary_span]
356+
#[label]
357+
#[suggestion(code = "", applicability = "maybe-incorrect")]
358+
pub span: Span,
359+
}
360+
352361
#[derive(Diagnostic)]
353362
#[diag(ast_lowering_never_pattern_with_guard)]
354363
pub struct NeverPatternWithGuard {

compiler/rustc_ast_lowering/src/expr.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use super::errors::{
22
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
33
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
44
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
5-
NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
5+
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
6+
UnderscoreExprLhsAssign,
67
};
78
use super::ResolverAstLoweringExt;
89
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
@@ -567,20 +568,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
567568
let hir_id = self.next_id();
568569
let span = self.lower_span(arm.span);
569570
self.lower_attrs(hir_id, &arm.attrs);
570-
let body = if let Some(body) = &arm.body {
571-
// FIXME(never_patterns): Disallow never pattern with a body or guard
571+
let is_never_pattern = pat.is_never_pattern();
572+
let body = if let Some(body) = &arm.body
573+
&& !is_never_pattern
574+
{
572575
self.lower_expr(body)
573576
} else {
574-
if !pat.is_never_pattern() {
575-
self.tcx
576-
.sess
577-
.emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() });
577+
// Either `body.is_none()` or `is_never_pattern` here.
578+
if !is_never_pattern {
579+
let suggestion = span.shrink_to_hi();
580+
self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
581+
} else if let Some(body) = &arm.body {
582+
self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span });
583+
guard = None;
578584
} else if let Some(g) = &arm.guard {
579585
self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span });
580586
guard = None;
581587
}
582588

583-
// An arm without a body, meant for never patterns.
584589
// We add a fake `loop {}` arm body so that it typecks to `!`.
585590
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
586591
let block = self.arena.alloc(hir::Block {

tests/ui/feature-gates/feature-gate-never_patterns.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn main() {
1212
unsafe {
1313
let ptr: *const Void = NonNull::dangling().as_ptr();
1414
match *ptr {
15-
! => {} //~ ERROR `!` patterns are experimental
15+
! //~ ERROR `!` patterns are experimental
1616
}
1717
}
1818

tests/ui/feature-gates/feature-gate-never_patterns.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ LL | let (Ok(_x) | Err(&!)) = res.as_ref();
1818
error[E0658]: `!` patterns are experimental
1919
--> $DIR/feature-gate-never_patterns.rs:15:13
2020
|
21-
LL | ! => {}
21+
LL | !
2222
| ^
2323
|
2424
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information

tests/ui/never_patterns/check.rs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ macro_rules! never {
1212
fn no_arms_or_guards(x: Void) {
1313
match None::<Void> {
1414
Some(!) => {}
15+
//~^ ERROR a never pattern is always unreachable
1516
None => {}
1617
}
1718
match None::<Void> {
@@ -21,10 +22,12 @@ fn no_arms_or_guards(x: Void) {
2122
}
2223
match None::<Void> {
2324
Some(!) if true => {}
25+
//~^ ERROR a never pattern is always unreachable
2426
None => {}
2527
}
2628
match None::<Void> {
2729
Some(never!()) => {},
30+
//~^ ERROR a never pattern is always unreachable
2831
None => {}
2932
}
3033
}

tests/ui/never_patterns/check.stderr

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
1+
error: a never pattern is always unreachable
2+
--> $DIR/check.rs:14:20
3+
|
4+
LL | Some(!) => {}
5+
| ^^
6+
| |
7+
| this will never be executed
8+
| help: remove this expression
9+
110
error: a guard on a never pattern will never be run
2-
--> $DIR/check.rs:18:20
11+
--> $DIR/check.rs:19:20
312
|
413
LL | Some(!) if true,
514
| ^^^^ help: remove this guard
615

7-
error: aborting due to 1 previous error
16+
error: a never pattern is always unreachable
17+
--> $DIR/check.rs:24:28
18+
|
19+
LL | Some(!) if true => {}
20+
| ^^
21+
| |
22+
| this will never be executed
23+
| help: remove this expression
24+
25+
error: a never pattern is always unreachable
26+
--> $DIR/check.rs:29:27
27+
|
28+
LL | Some(never!()) => {},
29+
| ^^
30+
| |
31+
| this will never be executed
32+
| help: remove this expression
33+
34+
error: aborting due to 4 previous errors
835

tests/ui/pattern/never_patterns.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -20,58 +20,58 @@ fn never_pattern_location(void: Void) {
2020
// FIXME(never_patterns): Don't accept on a non-empty type.
2121
match Some(0) {
2222
None => {}
23-
Some(!) => {}
23+
Some(!),
2424
}
2525
// FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches.
2626
match () {
2727
() => {}
28-
! => {}
28+
!,
2929
}
3030
// FIXME(never_patterns): Don't accept even on an empty branch.
3131
match None::<Void> {
3232
None => {}
33-
! => {}
33+
!,
3434
}
3535
// FIXME(never_patterns): Let alone if the emptiness is behind a reference.
3636
match None::<&Void> {
3737
None => {}
38-
! => {}
38+
!,
3939
}
4040
// Participate in match ergonomics.
4141
match &void {
42-
! => {}
42+
!
4343
}
4444
match &&void {
45-
! => {}
45+
!
4646
}
4747
match &&void {
48-
&! => {}
48+
&!
4949
}
5050
match &None::<Void> {
5151
None => {}
52-
Some(!) => {}
52+
Some(!)
5353
}
5454
match None::<&Void> {
5555
None => {}
56-
Some(!) => {}
56+
Some(!),
5757
}
5858
// Accept on a composite empty type.
5959
match None::<&(u32, Void)> {
6060
None => {}
61-
Some(&!) => {}
61+
Some(&!),
6262
}
6363
// Accept on an simple empty type.
6464
match None::<Void> {
6565
None => {}
66-
Some(!) => {}
66+
Some(!),
6767
}
6868
match None::<&Void> {
6969
None => {}
70-
Some(&!) => {}
70+
Some(&!),
7171
}
7272
match None::<&(u32, Void)> {
7373
None => {}
74-
Some(&(_, !)) => {}
74+
Some(&(_, !)),
7575
}
7676
}
7777

@@ -89,7 +89,7 @@ fn never_and_bindings() {
8989
// FIXME(never_patterns): A never pattern mustn't have bindings.
9090
match x {
9191
Ok(_) => {}
92-
Err(&(_b, !)) => {}
92+
Err(&(_b, !)),
9393
}
9494
match x {
9595
Ok(_a) | Err(&(_b, !)) => {}

0 commit comments

Comments
 (0)