Skip to content

Commit 7d9e070

Browse files
committed
Disallow an arm without a body (except for never patterns)
Parsing now accepts a match arm without a body, so we must make sure to only accept that if the pattern is a never pattern.
1 parent 0aa55c1 commit 7d9e070

File tree

9 files changed

+128
-12
lines changed

9 files changed

+128
-12
lines changed

compiler/rustc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -659,8 +659,8 @@ impl Pat {
659659
matches!(self.kind, PatKind::Rest)
660660
}
661661

662-
/// Could this be a never pattern? I.e. is it a never pattern modulo macro invocations that
663-
/// might return never patterns?
662+
/// Whether this could be a never pattern, taking into account that a macro invocation can
663+
/// return a never pattern. Used to inform errors during parsing.
664664
pub fn could_be_never_pattern(&self) -> bool {
665665
let mut could_be_never_pattern = false;
666666
self.walk(&mut |pat| match &pat.kind {

compiler/rustc_ast_lowering/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ ast_lowering_invalid_register =
9191
ast_lowering_invalid_register_class =
9292
invalid register class `{$reg_class}`: {$error}
9393
94+
ast_lowering_match_arm_with_no_body =
95+
`match` arm with no body
96+
.suggestion = add a body after the pattern
97+
9498
ast_lowering_misplaced_assoc_ty_binding =
9599
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
96100

compiler/rustc_ast_lowering/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,15 @@ pub struct NotSupportedForLifetimeBinderAsyncClosure {
340340
pub span: Span,
341341
}
342342

343+
#[derive(Diagnostic)]
344+
#[diag(ast_lowering_match_arm_with_no_body)]
345+
pub struct MatchArmWithNoBody {
346+
#[primary_span]
347+
pub span: Span,
348+
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
349+
pub suggestion: Span,
350+
}
351+
343352
#[derive(Diagnostic, Clone, Copy)]
344353
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
345354
pub struct ArbitraryExpressionInPattern {

compiler/rustc_ast_lowering/src/expr.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::errors::{
22
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
33
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
4-
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd,
4+
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
55
NotSupportedForLifetimeBinderAsyncClosure, UnderscoreExprLhsAssign,
66
};
77
use super::ResolverAstLoweringExt;
@@ -565,14 +565,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
565565
}
566566
});
567567
let hir_id = self.next_id();
568+
let span = self.lower_span(arm.span);
568569
self.lower_attrs(hir_id, &arm.attrs);
569570
let body = if let Some(body) = &arm.body {
571+
// FIXME(never_patterns): Disallow never pattern with a body or guard
570572
self.lower_expr(body)
571573
} else {
574+
if !pat.is_never_pattern() {
575+
self.tcx
576+
.sess
577+
.emit_err(MatchArmWithNoBody { span, suggestion: span.shrink_to_hi() });
578+
}
579+
572580
// An arm without a body, meant for never patterns.
573581
// We add a fake `loop {}` arm body so that it typecks to `!`.
574582
// FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`.
575-
let span = pat.span;
576583
let block = self.arena.alloc(hir::Block {
577584
stmts: &[],
578585
expr: None,
@@ -587,7 +594,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
587594
span,
588595
})
589596
};
590-
hir::Arm { hir_id, pat, guard, body, span: self.lower_span(arm.span) }
597+
hir::Arm { hir_id, pat, guard, body, span }
591598
}
592599

593600
/// Lower an `async` construct to a coroutine that implements `Future`.

compiler/rustc_hir/src/hir.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,23 @@ impl<'hir> Pat<'hir> {
10551055
true
10561056
})
10571057
}
1058+
1059+
/// Whether this a never pattern.
1060+
pub fn is_never_pattern(&self) -> bool {
1061+
let mut is_never_pattern = false;
1062+
self.walk(|pat| match &pat.kind {
1063+
PatKind::Never => {
1064+
is_never_pattern = true;
1065+
false
1066+
}
1067+
PatKind::Or(s) => {
1068+
is_never_pattern = s.iter().all(|p| p.is_never_pattern());
1069+
false
1070+
}
1071+
_ => true,
1072+
});
1073+
is_never_pattern
1074+
}
10581075
}
10591076

10601077
/// A single field in a struct pattern.

tests/ui/parser/macro/macro-expand-to-match-arm.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fn main() {
1313
Some(1) => {},
1414
arm!(None => {}),
1515
//~^ NOTE caused by the macro expansion here
16+
//~| ERROR `match` arm with no body
1617
Some(2) => {},
1718
_ => {},
1819
};

tests/ui/parser/macro/macro-expand-to-match-arm.stderr

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,11 @@ LL | arm!(None => {}),
1010
= note: the usage of `arm!` is likely invalid in pattern context
1111
= note: macros cannot expand to match arms
1212

13-
error: aborting due to 1 previous error
13+
error: `match` arm with no body
14+
--> $DIR/macro-expand-to-match-arm.rs:14:9
15+
|
16+
LL | arm!(None => {}),
17+
| ^^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
18+
19+
error: aborting due to 2 previous errors
1420

tests/ui/parser/match-arm-without-body.rs

+18
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ macro_rules! pat {
55
fn main() {
66
match Some(false) {
77
Some(_)
8+
//~^ ERROR `match` arm with no body
9+
//~| HELP add a body after the pattern
810
}
911
match Some(false) {
1012
Some(_)
@@ -26,6 +28,8 @@ fn main() {
2628
}
2729
match Some(false) {
2830
Some(_) if true
31+
//~^ ERROR `match` arm with no body
32+
//~| HELP add a body after the pattern
2933
}
3034
match Some(false) {
3135
Some(_) if true
@@ -34,28 +38,42 @@ fn main() {
3438
}
3539
match Some(false) {
3640
Some(_) if true,
41+
//~^ ERROR `match` arm with no body
42+
//~| HELP add a body after the pattern
3743
}
3844
match Some(false) {
3945
Some(_) if true,
46+
//~^ ERROR `match` arm with no body
47+
//~| HELP add a body after the pattern
4048
_ => {}
4149
}
4250
match Some(false) {
4351
pat!()
52+
//~^ ERROR `match` arm with no body
53+
//~| HELP add a body after the pattern
4454
}
4555
match Some(false) {
4656
pat!(),
57+
//~^ ERROR `match` arm with no body
58+
//~| HELP add a body after the pattern
4759
}
4860
match Some(false) {
4961
pat!() if true,
62+
//~^ ERROR `match` arm with no body
63+
//~| HELP add a body after the pattern
5064
}
5165
match Some(false) {
5266
pat!()
5367
//~^ ERROR expected `,` following `match` arm
5468
//~| HELP missing a comma here
69+
//~| ERROR `match` arm with no body
70+
//~| HELP add a body after the pattern
5571
_ => {}
5672
}
5773
match Some(false) {
5874
pat!(),
75+
//~^ ERROR `match` arm with no body
76+
//~| HELP add a body after the pattern
5977
_ => {}
6078
}
6179
}

tests/ui/parser/match-arm-without-body.stderr

+60-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error: expected one of `,`, `=>`, `if`, `|`, or `}`, found reserved identifier `_`
2-
--> $DIR/match-arm-without-body.rs:11:9
2+
--> $DIR/match-arm-without-body.rs:13:9
33
|
44
LL | Some(_)
55
| - expected one of `,`, `=>`, `if`, `|`, or `}`
66
LL | _ => {}
77
| ^ unexpected token
88

99
error: unexpected `,` in pattern
10-
--> $DIR/match-arm-without-body.rs:15:16
10+
--> $DIR/match-arm-without-body.rs:17:16
1111
|
1212
LL | Some(_),
1313
| ^
@@ -22,7 +22,7 @@ LL | Some(_) |
2222
|
2323

2424
error: unexpected `,` in pattern
25-
--> $DIR/match-arm-without-body.rs:21:16
25+
--> $DIR/match-arm-without-body.rs:23:16
2626
|
2727
LL | Some(_),
2828
| ^
@@ -45,18 +45,72 @@ LL ~ _ => {}
4545
|
4646

4747
error: expected one of `,`, `.`, `=>`, `?`, `}`, or an operator, found reserved identifier `_`
48-
--> $DIR/match-arm-without-body.rs:32:9
48+
--> $DIR/match-arm-without-body.rs:36:9
4949
|
5050
LL | Some(_) if true
5151
| - expected one of `,`, `.`, `=>`, `?`, `}`, or an operator
5252
LL | _ => {}
5353
| ^ unexpected token
5454

5555
error: expected `,` following `match` arm
56-
--> $DIR/match-arm-without-body.rs:52:15
56+
--> $DIR/match-arm-without-body.rs:66:15
5757
|
5858
LL | pat!()
5959
| ^ help: missing a comma here to end this `match` arm: `,`
6060

61-
error: aborting due to 5 previous errors
61+
error: `match` arm with no body
62+
--> $DIR/match-arm-without-body.rs:7:9
63+
|
64+
LL | Some(_)
65+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
66+
67+
error: `match` arm with no body
68+
--> $DIR/match-arm-without-body.rs:30:9
69+
|
70+
LL | Some(_) if true
71+
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
72+
73+
error: `match` arm with no body
74+
--> $DIR/match-arm-without-body.rs:40:9
75+
|
76+
LL | Some(_) if true,
77+
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
78+
79+
error: `match` arm with no body
80+
--> $DIR/match-arm-without-body.rs:45:9
81+
|
82+
LL | Some(_) if true,
83+
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
84+
85+
error: `match` arm with no body
86+
--> $DIR/match-arm-without-body.rs:51:9
87+
|
88+
LL | pat!()
89+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
90+
91+
error: `match` arm with no body
92+
--> $DIR/match-arm-without-body.rs:56:9
93+
|
94+
LL | pat!(),
95+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
96+
97+
error: `match` arm with no body
98+
--> $DIR/match-arm-without-body.rs:61:9
99+
|
100+
LL | pat!() if true,
101+
| ^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
102+
103+
error: `match` arm with no body
104+
--> $DIR/match-arm-without-body.rs:66:9
105+
|
106+
LL | pat!()
107+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
108+
109+
error: `match` arm with no body
110+
--> $DIR/match-arm-without-body.rs:74:9
111+
|
112+
LL | pat!(),
113+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
114+
115+
error: aborting due to 14 previous errors
62116

0 commit comments

Comments
 (0)