Skip to content

Commit

Permalink
Auto merge of #29850 - Kimundi:attributes_that_make_a_statement, r=pn…
Browse files Browse the repository at this point in the history
…kfelix

See rust-lang/rfcs#16 and #15701

- Added syntax support for attributes on expressions and all syntax nodes in statement position.
- Extended `#[cfg]` folder to allow removal of statements, and
of expressions in optional positions like expression lists and trailing
block expressions.
- Extended lint checker to recognize lint levels on expressions and
locals.
- As per RFC, attributes are not yet accepted on `if` expressions.

Examples:
  ```rust
let x = y;
{
        ...
}
assert_eq!((1, #[cfg(unset)] 2, 3), (1, 3));

let FOO = 0;
```

Implementation wise, there are a few rough corners and open questions:
- The parser work ended up a bit ugly.
- The pretty printer change was based mostly on guessing.
- Similar to the `if` case, there are some places in the grammar where a new `Expr` node starts,
  but where it seemed weird to accept attributes and hence the parser doesn't. This includes:
  - const expressions in patterns
  - in the middle of an postfix operator chain (that is, after `.`, before indexing, before calls)
  - on range expressions, since `#[attr] x .. y` parses as  `(#[attr] x) .. y`, which is inconsistent with
    `#[attr] .. y` which would parse as `#[attr] (.. y)`
- Attributes are added as additional `Option<Box<Vec<Attribute>>>` fields in expressions and locals.
- Memory impact has not been measured yet.
- A cfg-away trailing expression in a block does not currently promote the previous `StmtExpr` in a block to a new trailing expr. That is to say, this won't work:
```rust
let x = {
    #[cfg(foo)]
    Foo { data: x }
    #[cfg(not(foo))]
    Foo { data: y }
};
```
- One-element tuples can have their inner expression removed to become Unit, but just Parenthesis can't. Eg, `(#[cfg(unset)] x,) == ()` but `(#[cfg(unset)] x) == error`. This seemed reasonable to me since tuples and unit are type constructors, but could probably be argued either way.
- Attributes on macro nodes are currently unconditionally dropped during macro expansion, which seemed fine since macro disappear at that point?
- Attributes on `ast::ExprParens` will be prepend-ed to the inner expression in the hir folder.
- The work on pretty printer tests for this did trigger, but not fix errors regarding macros:
  - expression `foo![]` prints as `foo!()`
  - expression `foo!{}` prints as `foo!()`
  - statement `foo![];` prints as `foo!();`
  - statement `foo!{};` prints as `foo!();`
  - statement `foo!{}` triggers a `None` unwrap ICE.
  • Loading branch information
bors committed Dec 4, 2015
2 parents 5673a7b + d06f480 commit 77ed39c
Show file tree
Hide file tree
Showing 45 changed files with 2,283 additions and 586 deletions.
3 changes: 3 additions & 0 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2368,6 +2368,9 @@ The currently implemented features of the reference compiler are:
influence type inference.
* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.

* - `stmt_expr_attributes` - Allows attributes on expressions and
non-item statements.

If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about `#![feature]` directives which enabled
the new feature (because the directive is no longer necessary). However, if a
Expand Down
18 changes: 14 additions & 4 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast;
use syntax::attr::ThinAttributesExt;
use rustc_front::hir;
use rustc_front::util;
use rustc_front::intravisit as hir_visit;
Expand Down Expand Up @@ -674,11 +675,18 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
}

fn visit_expr(&mut self, e: &hir::Expr) {
run_lints!(self, check_expr, late_passes, e);
hir_visit::walk_expr(self, e);
self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
})
}

fn visit_stmt(&mut self, s: &hir::Stmt) {
// statement attributes are actually just attributes on one of
// - item
// - local
// - expression
// so we keep track of lint levels there
run_lints!(self, check_stmt, late_passes, s);
hir_visit::walk_stmt(self, s);
}
Expand Down Expand Up @@ -730,8 +738,10 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
}

fn visit_local(&mut self, l: &hir::Local) {
run_lints!(self, check_local, late_passes, l);
hir_visit::walk_local(self, l);
self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
run_lints!(cx, check_local, late_passes, l);
hir_visit::walk_local(cx, l);
})
}

fn visit_block(&mut self, b: &hir::Block) {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
P(hir::Expr {
id: 0,
node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
span: DUMMY_SP
span: DUMMY_SP,
attrs: None,
})
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ impl fold::Folder for ReplaceBodyWithLoop {
node: ast::ExprLoop(empty_block, None),
id: ast::DUMMY_NODE_ID,
span: codemap::DUMMY_SP,
attrs: None,
});

expr_to_block(b.rules, Some(loop_expr))
Expand Down
51 changes: 12 additions & 39 deletions src/librustc_front/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,13 @@
use hir::*;
use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
use syntax::ast::{MetaWord, MetaList, MetaNameValue};
use syntax::attr::ThinAttributesExt;
use hir;
use syntax::codemap::{respan, Span, Spanned};
use syntax::owned_slice::OwnedSlice;
use syntax::ptr::P;
use syntax::parse::token;
use std::ptr;

// This could have a better place to live.
pub trait MoveMap<T> {
fn move_map<F>(self, f: F) -> Self where F: FnMut(T) -> T;
}

impl<T> MoveMap<T> for Vec<T> {
fn move_map<F>(mut self, mut f: F) -> Vec<T>
where F: FnMut(T) -> T
{
for p in &mut self {
unsafe {
// FIXME(#5016) this shouldn't need to zero to be safe.
ptr::write(p, f(ptr::read_and_drop(p)));
}
}
self
}
}

impl<T> MoveMap<T> for OwnedSlice<T> {
fn move_map<F>(self, f: F) -> OwnedSlice<T>
where F: FnMut(T) -> T
{
OwnedSlice::from_vec(self.into_vec().move_map(f))
}
}
use syntax::util::move_map::MoveMap;

pub trait Folder : Sized {
// Any additions to this trait should happen in form
Expand Down Expand Up @@ -332,7 +306,7 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<
}

pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
attrs.into_iter().flat_map(|x| fld.fold_attribute(x)).collect()
attrs.move_flat_map(|x| fld.fold_attribute(x))
}

pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm {
Expand Down Expand Up @@ -501,13 +475,14 @@ pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedPara
}

pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
l.map(|Local { id, pat, ty, init, span }| {
l.map(|Local { id, pat, ty, init, span, attrs }| {
Local {
id: fld.new_id(id),
ty: ty.map(|t| fld.fold_ty(t)),
pat: fld.fold_pat(pat),
init: init.map(|e| fld.fold_expr(e)),
span: fld.new_span(span),
attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, fld)),
}
})
}
Expand Down Expand Up @@ -769,7 +744,7 @@ pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block { id, stmts, expr, rules, span }| {
Block {
id: folder.new_id(id),
stmts: stmts.into_iter().map(|s| folder.fold_stmt(s)).collect(),
stmts: stmts.move_map(|s| folder.fold_stmt(s)),
expr: expr.map(|x| folder.fold_expr(x)),
rules: rules,
span: folder.new_span(span),
Expand Down Expand Up @@ -816,9 +791,8 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
}
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
let new_impl_items = impl_items.into_iter()
.map(|item| folder.fold_impl_item(item))
.collect();
let new_impl_items = impl_items
.move_map(|item| folder.fold_impl_item(item));
let ifce = match ifce {
None => None,
Some(ref trait_ref) => {
Expand All @@ -834,9 +808,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
}
ItemTrait(unsafety, generics, bounds, items) => {
let bounds = folder.fold_bounds(bounds);
let items = items.into_iter()
.map(|item| folder.fold_trait_item(item))
.collect();
let items = items.move_map(|item| folder.fold_trait_item(item));
ItemTrait(unsafety, folder.fold_generics(generics), bounds, items)
}
}
Expand Down Expand Up @@ -892,7 +864,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T) -> P<ImplI
pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod {
Mod {
inner: folder.new_span(inner),
item_ids: item_ids.into_iter().map(|x| folder.fold_item_id(x)).collect(),
item_ids: item_ids.move_map(|x| folder.fold_item_id(x)),
}
}

Expand Down Expand Up @@ -1048,7 +1020,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
})
}

pub fn noop_fold_expr<T: Folder>(Expr { id, node, span }: Expr, folder: &mut T) -> Expr {
pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr {
Expr {
id: folder.new_id(id),
node: match node {
Expand Down Expand Up @@ -1171,6 +1143,7 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span }: Expr, folder: &mut T)
}
},
span: folder.new_span(span),
attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, folder)),
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_front/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId};
use syntax::abi::Abi;
use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, CrateConfig};
use syntax::attr::ThinAttributes;
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
Expand Down Expand Up @@ -558,6 +559,7 @@ pub struct Local {
pub init: Option<P<Expr>>,
pub id: NodeId,
pub span: Span,
pub attrs: ThinAttributes,
}

pub type Decl = Spanned<Decl_>;
Expand Down Expand Up @@ -609,6 +611,7 @@ pub struct Expr {
pub id: NodeId,
pub node: Expr_,
pub span: Span,
pub attrs: ThinAttributes,
}

impl fmt::Debug for Expr {
Expand Down
1 change: 0 additions & 1 deletion src/librustc_front/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(str_char)]
#![feature(filling_drop)]

extern crate serialize;
#[macro_use]
Expand Down
Loading

0 comments on commit 77ed39c

Please sign in to comment.