Skip to content

Commit d40202d

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

File tree

7 files changed

+145
-13
lines changed

7 files changed

+145
-13
lines changed

Diff for: 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;

Diff for: 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

Diff for: 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+
}

Diff for: compiler/rustc_ast_passes/src/feature_gate.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,36 @@ 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(span_lines) = sm.span_to_lines(span)
569+
&& let [line_info] = span_lines.lines.as_slice()
570+
&& let Some(line) = span_lines.file.get_line(line_info.line_index)
571+
&& &line[line_info.start_col.0..line_info.end_col.0] == "!"
572+
{
573+
feature_err(
574+
&sess.parse_sess,
575+
sym::never_patterns,
576+
span,
577+
"`!` patterns are experimental",
578+
)
579+
.emit();
580+
} else {
581+
let suggestion = span.shrink_to_hi();
582+
sess.emit_err(errors::MatchArmWithNoBody { span, suggestion });
583+
}
584+
}
585+
}
586+
}
558587

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

Diff for: 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).

Diff for: tests/ui/feature-gates/feature-gate-never_patterns.rs

+33-7
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,42 @@ 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 `match` arm with no body
38+
}
39+
match res {
40+
Ok(_) => {}
41+
Err(!)
42+
//~^ ERROR `match` arm with no body
43+
//~| ERROR `!` patterns are experimental
44+
}
45+
1946
// 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-
}
47+
match Some(0) {
48+
None => {}
49+
#[cfg(FALSE)]
50+
Some(_)
51+
//~^ ERROR `match` arm with no body
2652
}
2753
}

Diff for: tests/ui/feature-gates/feature-gate-never_patterns.stderr

+58-2
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,71 @@ LL | !
2525
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
2626

2727
error[E0658]: `!` patterns are experimental
28-
--> $DIR/feature-gate-never_patterns.rs:24:13
28+
--> $DIR/feature-gate-never_patterns.rs:15:13
29+
|
30+
LL | !
31+
| ^
32+
|
33+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
34+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
35+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
36+
37+
error[E0658]: `!` patterns are experimental
38+
--> $DIR/feature-gate-never_patterns.rs:22:13
39+
|
40+
LL | !
41+
| ^
42+
|
43+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
44+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
45+
46+
error[E0658]: `!` patterns are experimental
47+
--> $DIR/feature-gate-never_patterns.rs:22:13
48+
|
49+
LL | !
50+
| ^
51+
|
52+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
53+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
54+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
55+
56+
error[E0658]: `!` patterns are experimental
57+
--> $DIR/feature-gate-never_patterns.rs:28:13
2958
|
3059
LL | ! => {}
3160
| ^
3261
|
3362
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
3463
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
3564

36-
error: aborting due to 4 previous errors
65+
error: `match` arm with no body
66+
--> $DIR/feature-gate-never_patterns.rs:36:9
67+
|
68+
LL | Some(_)
69+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
70+
71+
error[E0658]: `!` patterns are experimental
72+
--> $DIR/feature-gate-never_patterns.rs:41:13
73+
|
74+
LL | Err(!)
75+
| ^
76+
|
77+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
78+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
79+
80+
error: `match` arm with no body
81+
--> $DIR/feature-gate-never_patterns.rs:41:9
82+
|
83+
LL | Err(!)
84+
| ^^^^^^- help: add a body after the pattern: `=> todo!(),`
85+
86+
error: `match` arm with no body
87+
--> $DIR/feature-gate-never_patterns.rs:50:9
88+
|
89+
LL | Some(_)
90+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
91+
92+
error: aborting due to 11 previous errors
3793

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

0 commit comments

Comments
 (0)