Skip to content

Commit f63b88c

Browse files
committed
Permit attributes on 'if' expressions
Previously, attributes on 'if' expressions (e.g. #[attr] if true {}) were disallowed during parsing. This made it impossible for macros to perform any custom handling of such attributes (e.g. stripping them away), since a compilation error would be emitted before they ever had a chance to run. This PR permits attributes on 'if' expressions ('if-attrs' from here on). Both built-in attributes (e.g. `#[allow]`, `#[cfg]`) are supported. We still do *not* accept attributes on 'other parts' of an if-else chain. That is, the following code snippet still fails to parse: ```rust if true {} #[attr] else if false {} else #[attr] if false {} #[attr] else {} ```
1 parent 2b0cfa5 commit f63b88c

File tree

10 files changed

+137
-34
lines changed

10 files changed

+137
-34
lines changed

src/librustc_parse/parser/expr.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -665,20 +665,11 @@ impl<'a> Parser<'a> {
665665
expr.map(|mut expr| {
666666
attrs.extend::<Vec<_>>(expr.attrs.into());
667667
expr.attrs = attrs;
668-
self.error_attr_on_if_expr(&expr);
669668
expr
670669
})
671670
})
672671
}
673672

674-
fn error_attr_on_if_expr(&self, expr: &Expr) {
675-
if let (ExprKind::If(..), [a0, ..]) = (&expr.kind, &*expr.attrs) {
676-
// Just point to the first attribute in there...
677-
self.struct_span_err(a0.span, "attributes are not yet allowed on `if` expressions")
678-
.emit();
679-
}
680-
}
681-
682673
fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
683674
loop {
684675
if self.eat(&token::Question) {

src/test/pretty/if-attr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// pp-exact
2+
3+
#[cfg(FALSE)]
4+
fn simple_attr() {
5+
6+
#[attr]
7+
if true { }
8+
9+
#[allow_warnings]
10+
if true { }
11+
}
12+
13+
#[cfg(FALSE)]
14+
fn if_else_chain() {
15+
16+
#[first_attr]
17+
if true { } else if false { } else { }
18+
}
19+
20+
#[cfg(FALSE)]
21+
fn if_let() {
22+
23+
#[attr]
24+
if let Some(_) = Some(true) { }
25+
}
26+
27+
28+
fn main() { }

src/test/ui/parser/attr-stmt-expr-attr-bad.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ fn main() {}
3838
//~^ ERROR an inner attribute is not permitted in this context
3939
#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
4040
//~^ ERROR an inner attribute is not permitted in this context
41-
#[cfg(FALSE)] fn e() { let _ = #[attr] if 0 {}; }
42-
//~^ ERROR attributes are not yet allowed on `if` expressions
4341
#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
4442
//~^ ERROR expected `{`, found `#`
4543
#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
@@ -51,14 +49,11 @@ fn main() {}
5149
#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
5250
//~^ ERROR an inner attribute is not permitted in this context
5351
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
54-
//~^ ERROR attributes are not yet allowed on `if` expressions
55-
//~| ERROR expected `{`, found `#`
52+
//~^ ERROR expected `{`, found `#`
5653
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
5754
//~^ ERROR expected `{`, found `#`
5855
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
5956
//~^ ERROR an inner attribute is not permitted in this context
60-
#[cfg(FALSE)] fn e() { let _ = #[attr] if let _ = 0 {}; }
61-
//~^ ERROR attributes are not yet allowed on `if` expressions
6257
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
6358
//~^ ERROR expected `{`, found `#`
6459
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
@@ -70,8 +65,7 @@ fn main() {}
7065
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
7166
//~^ ERROR an inner attribute is not permitted in this context
7267
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
73-
//~^ ERROR attributes are not yet allowed on `if` expressions
74-
//~| ERROR expected `{`, found `#`
68+
//~^ ERROR expected `{`, found `#`
7569
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
7670
//~^ ERROR expected `{`, found `#`
7771
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// check-pass
2+
3+
#[cfg(FALSE)]
4+
fn simple_attr() {
5+
#[attr] if true {}
6+
#[allow_warnings] if true {}
7+
}
8+
9+
#[cfg(FALSE)]
10+
fn if_else_chain() {
11+
#[first_attr] if true {
12+
} else if false {
13+
} else {
14+
}
15+
}
16+
17+
#[cfg(FALSE)]
18+
fn if_let() {
19+
#[attr] if let Some(_) = Some(true) {}
20+
}
21+
22+
macro_rules! custom_macro {
23+
($expr:expr) => {}
24+
}
25+
26+
custom_macro! {
27+
#[attr] if true {}
28+
}
29+
30+
31+
fn main() {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#[cfg(FALSE)]
2+
fn if_else_parse_error() {
3+
if true {
4+
} #[attr] else if false { //~ ERROR expected
5+
}
6+
}
7+
8+
#[cfg(FALSE)]
9+
fn else_attr_ifparse_error() {
10+
if true {
11+
} else #[attr] if false { //~ ERROR expected
12+
} else {
13+
}
14+
}
15+
16+
#[cfg(FALSE)]
17+
fn else_parse_error() {
18+
if true {
19+
} else if false {
20+
} #[attr] else { //~ ERROR expected
21+
}
22+
}
23+
24+
fn main() {
25+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: expected expression, found keyword `else`
2+
--> $DIR/else-attrs.rs:4:15
3+
|
4+
LL | } #[attr] else if false {
5+
| ^^^^ expected expression
6+
7+
error: expected `{`, found `#`
8+
--> $DIR/else-attrs.rs:11:12
9+
|
10+
LL | } else #[attr] if false {
11+
| ^ expected `{`
12+
|
13+
help: try placing this code inside a block
14+
|
15+
LL | } else #[attr] { if false {
16+
LL | } else {
17+
LL | } }
18+
|
19+
20+
error: expected expression, found keyword `else`
21+
--> $DIR/else-attrs.rs:20:15
22+
|
23+
LL | } #[attr] else {
24+
| ^^^^ expected expression
25+
26+
error: aborting due to 3 previous errors
27+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// check-pass
2+
3+
#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
4+
5+
#[cfg(FALSE)]
6+
fn foo() {
7+
#[attr]
8+
if let Some(_) = Some(true) && let Ok(_) = Ok(1) {
9+
} else if let Some(false) = Some(true) {
10+
}
11+
}
12+
13+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
warning: the feature `let_chains` is incomplete and may cause the compiler to crash
2+
--> $DIR/let-chains-attr.rs:3:12
3+
|
4+
LL | #![feature(let_chains)]
5+
| ^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
fn main() {
22
#[attr] if true {};
33
//~^ ERROR cannot find attribute
4-
//~| ERROR attributes are not yet allowed on `if` expressions
54
#[attr] if true {};
65
//~^ ERROR cannot find attribute
7-
//~| ERROR attributes are not yet allowed on `if` expressions
86
let _recovery_witness: () = 0; //~ ERROR mismatched types
97
}
Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
1-
error: attributes are not yet allowed on `if` expressions
2-
--> $DIR/recovery-attr-on-if.rs:2:5
3-
|
4-
LL | #[attr] if true {};
5-
| ^^^^^^^
6-
7-
error: attributes are not yet allowed on `if` expressions
8-
--> $DIR/recovery-attr-on-if.rs:5:5
9-
|
10-
LL | #[attr] if true {};
11-
| ^^^^^^^
12-
131
error: cannot find attribute `attr` in this scope
14-
--> $DIR/recovery-attr-on-if.rs:5:7
2+
--> $DIR/recovery-attr-on-if.rs:4:7
153
|
164
LL | #[attr] if true {};
175
| ^^^^
@@ -23,13 +11,13 @@ LL | #[attr] if true {};
2311
| ^^^^
2412

2513
error[E0308]: mismatched types
26-
--> $DIR/recovery-attr-on-if.rs:8:33
14+
--> $DIR/recovery-attr-on-if.rs:6:33
2715
|
2816
LL | let _recovery_witness: () = 0;
2917
| -- ^ expected `()`, found integer
3018
| |
3119
| expected due to this
3220

33-
error: aborting due to 5 previous errors
21+
error: aborting due to 3 previous errors
3422

3523
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)