Skip to content

Commit e274372

Browse files
committed
Correctly gate the parsing of match arms without body
1 parent 21cce21 commit e274372

File tree

9 files changed

+227
-26
lines changed

9 files changed

+227
-26
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
581581
} else {
582582
// Either `body.is_none()` or `is_never_pattern` here.
583583
if !is_never_pattern {
584-
let suggestion = span.shrink_to_hi();
585-
self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
584+
if self.tcx.features().never_patterns {
585+
// If the feature is off we already emitted the error after parsing.
586+
let suggestion = span.shrink_to_hi();
587+
self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
588+
}
586589
} else if let Some(body) = &arm.body {
587590
self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span });
588591
guard = None;

compiler/rustc_ast_passes/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@ ast_passes_item_underscore = `{$kind}` items in this context need a name
174174
ast_passes_keyword_lifetime =
175175
lifetimes cannot use keyword names
176176
177+
ast_passes_match_arm_with_no_body =
178+
`match` arm with no body
179+
.suggestion = add a body after the pattern
180+
177181
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
178182
.help = consider using the `#[path]` attribute to specify filesystem path
179183

compiler/rustc_ast_passes/src/errors.rs

+9
Original file line numberDiff line numberDiff line change
@@ -758,3 +758,12 @@ pub struct AnonStructOrUnionNotAllowed {
758758
pub span: Span,
759759
pub struct_or_union: &'static str,
760760
}
761+
762+
#[derive(Diagnostic)]
763+
#[diag(ast_passes_match_arm_with_no_body)]
764+
pub struct MatchArmWithNoBody {
765+
#[primary_span]
766+
pub span: Span,
767+
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
768+
pub suggestion: Span,
769+
}

compiler/rustc_ast_passes/src/feature_gate.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,34 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
554554
gate_all!(explicit_tail_calls, "`become` expression is experimental");
555555
gate_all!(generic_const_items, "generic const items are experimental");
556556
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
557-
gate_all!(never_patterns, "`!` patterns are experimental");
557+
558+
if !visitor.features.never_patterns {
559+
if let Some(spans) = spans.get(&sym::never_patterns) {
560+
for &span in spans {
561+
if span.allows_unstable(sym::never_patterns) {
562+
continue;
563+
}
564+
let sm = sess.source_map();
565+
// We gate two types of spans: the span of a `!` pattern, and the span of a
566+
// match arm without a body. For the latter we want to give the user a normal
567+
// error.
568+
if let Ok(snippet) = sm.span_to_snippet(span)
569+
&& snippet == "!"
570+
{
571+
feature_err(
572+
&sess.parse_sess,
573+
sym::never_patterns,
574+
span,
575+
"`!` patterns are experimental",
576+
)
577+
.emit();
578+
} else {
579+
let suggestion = span.shrink_to_hi();
580+
sess.emit_err(errors::MatchArmWithNoBody { span, suggestion });
581+
}
582+
}
583+
}
584+
}
558585

559586
if !visitor.features.negative_bounds {
560587
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {

compiler/rustc_parse/src/parser/expr.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -2918,7 +2918,12 @@ impl<'a> Parser<'a> {
29182918
let mut result = if !is_fat_arrow && !is_almost_fat_arrow {
29192919
// A pattern without a body, allowed for never patterns.
29202920
arm_body = None;
2921-
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)])
2921+
this.expect_one_of(&[token::Comma], &[token::CloseDelim(Delimiter::Brace)]).map(
2922+
|x| {
2923+
this.sess.gated_spans.gate(sym::never_patterns, pat.span);
2924+
x
2925+
},
2926+
)
29222927
} else {
29232928
if let Err(mut err) = this.expect(&token::FatArrow) {
29242929
// We might have a `=>` -> `=` or `->` typo (issue #89396).

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

+58-7
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,67 @@ fn main() {
1212
unsafe {
1313
let ptr: *const Void = NonNull::dangling().as_ptr();
1414
match *ptr {
15-
! //~ ERROR `!` patterns are experimental
15+
!
16+
//~^ ERROR `!` patterns are experimental
17+
//~| ERROR `!` patterns are experimental
18+
}
19+
// Check that the gate operates even behind `cfg`.
20+
#[cfg(FALSE)]
21+
match *ptr {
22+
!
23+
//~^ ERROR `!` patterns are experimental
24+
//~| ERROR `!` patterns are experimental
25+
}
26+
#[cfg(FALSE)]
27+
match *ptr {
28+
! => {}
29+
//~^ ERROR `!` patterns are experimental
1630
}
1731
}
1832

33+
// Correctly gate match arms with no body.
34+
match Some(0) {
35+
None => {}
36+
Some(_),
37+
//~^ ERROR unexpected `,` in pattern
38+
}
39+
match Some(0) {
40+
None => {}
41+
Some(_)
42+
//~^ ERROR `match` arm with no body
43+
}
44+
match Some(0) {
45+
_ => {}
46+
Some(_) if false,
47+
//~^ ERROR `match` arm with no body
48+
Some(_) if false
49+
//~^ ERROR `match` arm with no body
50+
}
51+
match res {
52+
Ok(_) => {}
53+
Err(!),
54+
//~^ ERROR `match` arm with no body
55+
//~| ERROR `!` patterns are experimental
56+
}
57+
match res {
58+
Err(!) if false,
59+
//~^ ERROR `match` arm with no body
60+
//~| ERROR a guard on a never pattern will never be run
61+
//~| ERROR `!` patterns are experimental
62+
_ => {}
63+
}
64+
1965
// Check that the gate operates even behind `cfg`.
20-
#[cfg(FALSE)]
21-
unsafe {
22-
let ptr: *const Void = NonNull::dangling().as_ptr();
23-
match *ptr {
24-
! => {} //~ ERROR `!` patterns are experimental
25-
}
66+
match Some(0) {
67+
None => {}
68+
#[cfg(FALSE)]
69+
Some(_)
70+
//~^ ERROR `match` arm with no body
71+
}
72+
match Some(0) {
73+
_ => {}
74+
#[cfg(FALSE)]
75+
Some(_) if false
76+
//~^ ERROR `match` arm with no body
2677
}
2778
}

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

+112-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
error: unexpected `,` in pattern
2+
--> $DIR/feature-gate-never_patterns.rs:36:16
3+
|
4+
LL | Some(_),
5+
| ^
6+
|
7+
help: try adding parentheses to match on a tuple...
8+
|
9+
LL | (Some(_),)
10+
| + +
11+
help: ...or a vertical bar to match on multiple alternatives
12+
|
13+
LL | Some(_) |
14+
|
15+
116
error[E0408]: variable `_x` is not bound in all patterns
217
--> $DIR/feature-gate-never_patterns.rs:8:19
318
|
@@ -25,15 +40,110 @@ LL | !
2540
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
2641

2742
error[E0658]: `!` patterns are experimental
28-
--> $DIR/feature-gate-never_patterns.rs:24:13
43+
--> $DIR/feature-gate-never_patterns.rs:15:13
44+
|
45+
LL | !
46+
| ^
47+
|
48+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
49+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
50+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
51+
52+
error[E0658]: `!` patterns are experimental
53+
--> $DIR/feature-gate-never_patterns.rs:22:13
54+
|
55+
LL | !
56+
| ^
57+
|
58+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
59+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
60+
61+
error[E0658]: `!` patterns are experimental
62+
--> $DIR/feature-gate-never_patterns.rs:22:13
63+
|
64+
LL | !
65+
| ^
66+
|
67+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
68+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
69+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
70+
71+
error[E0658]: `!` patterns are experimental
72+
--> $DIR/feature-gate-never_patterns.rs:28:13
2973
|
3074
LL | ! => {}
3175
| ^
3276
|
3377
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
3478
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
3579

36-
error: aborting due to 4 previous errors
80+
error: `match` arm with no body
81+
--> $DIR/feature-gate-never_patterns.rs:41:9
82+
|
83+
LL | Some(_)
84+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
85+
86+
error: `match` arm with no body
87+
--> $DIR/feature-gate-never_patterns.rs:46:9
88+
|
89+
LL | Some(_) if false,
90+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
91+
92+
error: `match` arm with no body
93+
--> $DIR/feature-gate-never_patterns.rs:48:9
94+
|
95+
LL | Some(_) if false
96+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
97+
98+
error[E0658]: `!` patterns are experimental
99+
--> $DIR/feature-gate-never_patterns.rs:53:13
100+
|
101+
LL | Err(!),
102+
| ^
103+
|
104+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
105+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
106+
107+
error: `match` arm with no body
108+
--> $DIR/feature-gate-never_patterns.rs:53:9
109+
|
110+
LL | Err(!),
111+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
112+
113+
error[E0658]: `!` patterns are experimental
114+
--> $DIR/feature-gate-never_patterns.rs:58:13
115+
|
116+
LL | Err(!) if false,
117+
| ^
118+
|
119+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
120+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
121+
122+
error: `match` arm with no body
123+
--> $DIR/feature-gate-never_patterns.rs:58:9
124+
|
125+
LL | Err(!) if false,
126+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
127+
128+
error: `match` arm with no body
129+
--> $DIR/feature-gate-never_patterns.rs:69:9
130+
|
131+
LL | Some(_)
132+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
133+
134+
error: `match` arm with no body
135+
--> $DIR/feature-gate-never_patterns.rs:75:9
136+
|
137+
LL | Some(_) if false
138+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
139+
140+
error: a guard on a never pattern will never be run
141+
--> $DIR/feature-gate-never_patterns.rs:58:19
142+
|
143+
LL | Err(!) if false,
144+
| ^^^^^ help: remove this guard
145+
146+
error: aborting due to 18 previous errors
37147

38148
Some errors have detailed explanations: E0408, E0658.
39149
For more information about an error, try `rustc --explain E0408`.

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

-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,6 @@ fn main() {
6666
pat!()
6767
//~^ ERROR expected `,` following `match` arm
6868
//~| HELP missing a comma here
69-
//~| ERROR `match` arm with no body
70-
//~| HELP add a body after the pattern
7169
_ => {}
7270
}
7371
match Some(false) {

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

+5-11
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,19 @@ error: `match` arm with no body
6868
--> $DIR/match-arm-without-body.rs:30:9
6969
|
7070
LL | Some(_) if true
71-
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
71+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
7272

7373
error: `match` arm with no body
7474
--> $DIR/match-arm-without-body.rs:40:9
7575
|
7676
LL | Some(_) if true,
77-
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
77+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
7878

7979
error: `match` arm with no body
8080
--> $DIR/match-arm-without-body.rs:45:9
8181
|
8282
LL | Some(_) if true,
83-
| ^^^^^^^^^^^^^^^- help: add a body after the pattern: `=> todo!(),`
83+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
8484

8585
error: `match` arm with no body
8686
--> $DIR/match-arm-without-body.rs:51:9
@@ -98,19 +98,13 @@ error: `match` arm with no body
9898
--> $DIR/match-arm-without-body.rs:61:9
9999
|
100100
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!()
107101
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
108102

109103
error: `match` arm with no body
110-
--> $DIR/match-arm-without-body.rs:74:9
104+
--> $DIR/match-arm-without-body.rs:72:9
111105
|
112106
LL | pat!(),
113107
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
114108

115-
error: aborting due to 14 previous errors
109+
error: aborting due to 13 previous errors
116110

0 commit comments

Comments
 (0)