Skip to content

Commit 3485b66

Browse files
authored
Unrolled build for rust-lang#118868
Rollup merge of rust-lang#118868 - Nadrieril:correctly-gate-never_patterns-parsing, r=petrochenkov Correctly gate the parsing of match arms without body rust-lang#118527 accidentally allowed the following to parse on stable: ```rust match Some(0) { None => { foo(); } #[cfg(FALSE)] Some(_) } ``` This fixes that oversight. The way I choose which error to emit is the best I could think of, I'm open if you know a better way. r? `@petrochenkov` since you're the one who noticed
2 parents 835ed00 + 19e0c98 commit 3485b66

File tree

10 files changed

+207
-26
lines changed

10 files changed

+207
-26
lines changed

compiler/rustc_ast/src/ast.rs

+13
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,19 @@ impl Pat {
676676
});
677677
could_be_never_pattern
678678
}
679+
680+
/// Whether this contains a `!` pattern. This in particular means that a feature gate error will
681+
/// be raised if the feature is off. Used to avoid gating the feature twice.
682+
pub fn contains_never_pattern(&self) -> bool {
683+
let mut contains_never_pattern = false;
684+
self.walk(&mut |pat| {
685+
if matches!(pat.kind, PatKind::Never) {
686+
contains_never_pattern = true;
687+
}
688+
true
689+
});
690+
contains_never_pattern
691+
}
679692
}
680693

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

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -2918,7 +2918,15 @@ 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+
// Don't gate twice
2924+
if !pat.contains_never_pattern() {
2925+
this.sess.gated_spans.gate(sym::never_patterns, pat.span);
2926+
}
2927+
x
2928+
},
2929+
)
29222930
} else {
29232931
if let Err(mut err) = this.expect(&token::FatArrow) {
29242932
// We might have a `=>` -> `=` or `->` typo (issue #89396).

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

+54-7
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,63 @@ 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+
}
18+
// Check that the gate operates even behind `cfg`.
19+
#[cfg(FALSE)]
20+
match *ptr {
21+
!
22+
//~^ ERROR `!` patterns are experimental
23+
}
24+
#[cfg(FALSE)]
25+
match *ptr {
26+
! => {}
27+
//~^ ERROR `!` patterns are experimental
1628
}
1729
}
1830

31+
// Correctly gate match arms with no body.
32+
match Some(0) {
33+
None => {}
34+
Some(_),
35+
//~^ ERROR unexpected `,` in pattern
36+
}
37+
match Some(0) {
38+
None => {}
39+
Some(_)
40+
//~^ ERROR `match` arm with no body
41+
}
42+
match Some(0) {
43+
_ => {}
44+
Some(_) if false,
45+
//~^ ERROR `match` arm with no body
46+
Some(_) if false
47+
//~^ ERROR `match` arm with no body
48+
}
49+
match res {
50+
Ok(_) => {}
51+
Err(!),
52+
//~^ ERROR `!` patterns are experimental
53+
}
54+
match res {
55+
Err(!) if false,
56+
//~^ ERROR `!` patterns are experimental
57+
//~| ERROR a guard on a never pattern will never be run
58+
_ => {}
59+
}
60+
1961
// 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-
}
62+
match Some(0) {
63+
None => {}
64+
#[cfg(FALSE)]
65+
Some(_)
66+
//~^ ERROR `match` arm with no body
67+
}
68+
match Some(0) {
69+
_ => {}
70+
#[cfg(FALSE)]
71+
Some(_) if false
72+
//~^ ERROR `match` arm with no body
2673
}
2774
}

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

+80-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:34: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,78 @@ 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:21: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+
51+
error[E0658]: `!` patterns are experimental
52+
--> $DIR/feature-gate-never_patterns.rs:26:13
2953
|
3054
LL | ! => {}
3155
| ^
3256
|
3357
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
3458
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
3559

36-
error: aborting due to 4 previous errors
60+
error: `match` arm with no body
61+
--> $DIR/feature-gate-never_patterns.rs:39:9
62+
|
63+
LL | Some(_)
64+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
65+
66+
error: `match` arm with no body
67+
--> $DIR/feature-gate-never_patterns.rs:44:9
68+
|
69+
LL | Some(_) if false,
70+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
71+
72+
error: `match` arm with no body
73+
--> $DIR/feature-gate-never_patterns.rs:46:9
74+
|
75+
LL | Some(_) if false
76+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
77+
78+
error[E0658]: `!` patterns are experimental
79+
--> $DIR/feature-gate-never_patterns.rs:51:13
80+
|
81+
LL | Err(!),
82+
| ^
83+
|
84+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
85+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
86+
87+
error[E0658]: `!` patterns are experimental
88+
--> $DIR/feature-gate-never_patterns.rs:55:13
89+
|
90+
LL | Err(!) if false,
91+
| ^
92+
|
93+
= note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information
94+
= help: add `#![feature(never_patterns)]` to the crate attributes to enable
95+
96+
error: `match` arm with no body
97+
--> $DIR/feature-gate-never_patterns.rs:65:9
98+
|
99+
LL | Some(_)
100+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
101+
102+
error: `match` arm with no body
103+
--> $DIR/feature-gate-never_patterns.rs:71:9
104+
|
105+
LL | Some(_) if false
106+
| ^^^^^^^- help: add a body after the pattern: `=> todo!(),`
107+
108+
error: a guard on a never pattern will never be run
109+
--> $DIR/feature-gate-never_patterns.rs:55:19
110+
|
111+
LL | Err(!) if false,
112+
| ^^^^^ help: remove this guard
113+
114+
error: aborting due to 14 previous errors
37115

38116
Some errors have detailed explanations: E0408, E0658.
39117
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)