Skip to content

Commit

Permalink
Syntactically permit attributes on 'if' expressions
Browse files Browse the repository at this point in the history
Fixes rust-lang#68618

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)
syntactically, i.e. during parsing. We instead deny if-attrs
during AST validation, which occurs after all macro expansions have run.

This is a conservative change which allows more code to be processed by
macros. It does not commit us to *semantically* accepting if-attrs. For
example, the following code is not allowed even with this PR:

```rust
fn builtin_attr() {
    #[allow(warnings)] if true {}
}

fn custom_attr() {
    #[my_proc_macro_attr] if true {}
}
```

However, the following code *is* accepted

```rust
#[cfg(FALSE)]
fn foo() {
    #[allow(warnings)] if true {}
    #[my_custom_attr] if true {}
}

#[my_custom_attr]
fn use_within_body() {
    #[allow(warnings)] if true {}
    #[my_custom_attr] if true {}
}
```
  • Loading branch information
Aaron1011 committed Jan 29, 2020
1 parent 9ed29b6 commit bbe5133
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 8 deletions.
10 changes: 10 additions & 0 deletions src/librustc_ast_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,15 @@ impl<'a> AstValidator<'a> {
}
}
}

fn check_attr_on_if_expr(&self, attrs: &[Attribute]) {
if let [a0, ..] = attrs {
// Just point to the first attribute in there...
self.err_handler()
.struct_span_err(a0.span, "attributes are not yet allowed on `if` expressions")
.emit();
}
}
}

enum GenericPosition {
Expand Down Expand Up @@ -515,6 +524,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
)
.emit();
}
ExprKind::If(..) => self.check_attr_on_if_expr(&*expr.attrs),
_ => {}
}

Expand Down
8 changes: 0 additions & 8 deletions src/librustc_parse/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,19 +676,11 @@ impl<'a> Parser<'a> {
expr.map(|mut expr| {
attrs.extend::<Vec<_>>(expr.attrs.into());
expr.attrs = attrs;
self.error_attr_on_if_expr(&expr);
expr
})
})
}

fn error_attr_on_if_expr(&self, expr: &Expr) {
if let (ExprKind::If(..), [a0, ..]) = (&expr.kind, &*expr.attrs) {
// Just point to the first attribute in there...
self.struct_span_err(a0.span, "attributes are not yet allowed on `if` expressions")
.emit();
}
}

fn parse_dot_or_call_expr_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
loop {
Expand Down

0 comments on commit bbe5133

Please sign in to comment.