Skip to content

Commit 77ed39c

Browse files
committed
Auto merge of #29850 - Kimundi:attributes_that_make_a_statement, r=pnkfelix
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.
2 parents 5673a7b + d06f480 commit 77ed39c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2283
-586
lines changed

src/doc/reference.md

+3
Original file line numberDiff line numberDiff line change
@@ -2368,6 +2368,9 @@ The currently implemented features of the reference compiler are:
23682368
influence type inference.
23692369
* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.
23702370

2371+
* - `stmt_expr_attributes` - Allows attributes on expressions and
2372+
non-item statements.
2373+
23712374
If a feature is promoted to a language feature, then all existing programs will
23722375
start to receive compilation warnings about `#![feature]` directives which enabled
23732376
the new feature (because the directive is no longer necessary). However, if a

src/librustc/lint/context.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use syntax::attr::{self, AttrMetaMethods};
4242
use syntax::codemap::Span;
4343
use syntax::parse::token::InternedString;
4444
use syntax::ast;
45+
use syntax::attr::ThinAttributesExt;
4546
use rustc_front::hir;
4647
use rustc_front::util;
4748
use rustc_front::intravisit as hir_visit;
@@ -674,11 +675,18 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
674675
}
675676

676677
fn visit_expr(&mut self, e: &hir::Expr) {
677-
run_lints!(self, check_expr, late_passes, e);
678-
hir_visit::walk_expr(self, e);
678+
self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
679+
run_lints!(cx, check_expr, late_passes, e);
680+
hir_visit::walk_expr(cx, e);
681+
})
679682
}
680683

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

732740
fn visit_local(&mut self, l: &hir::Local) {
733-
run_lints!(self, check_local, late_passes, l);
734-
hir_visit::walk_local(self, l);
741+
self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
742+
run_lints!(cx, check_local, late_passes, l);
743+
hir_visit::walk_local(cx, l);
744+
})
735745
}
736746

737747
fn visit_block(&mut self, b: &hir::Block) {

src/librustc/middle/check_match.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
409409
P(hir::Expr {
410410
id: 0,
411411
node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })),
412-
span: DUMMY_SP
412+
span: DUMMY_SP,
413+
attrs: None,
413414
})
414415
}
415416

src/librustc_driver/pretty.rs

+1
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ impl fold::Folder for ReplaceBodyWithLoop {
654654
node: ast::ExprLoop(empty_block, None),
655655
id: ast::DUMMY_NODE_ID,
656656
span: codemap::DUMMY_SP,
657+
attrs: None,
657658
});
658659

659660
expr_to_block(b.rules, Some(loop_expr))

src/librustc_front/fold.rs

+12-39
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,13 @@
1414
use hir::*;
1515
use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
1616
use syntax::ast::{MetaWord, MetaList, MetaNameValue};
17+
use syntax::attr::ThinAttributesExt;
1718
use hir;
1819
use syntax::codemap::{respan, Span, Spanned};
1920
use syntax::owned_slice::OwnedSlice;
2021
use syntax::ptr::P;
2122
use syntax::parse::token;
22-
use std::ptr;
23-
24-
// This could have a better place to live.
25-
pub trait MoveMap<T> {
26-
fn move_map<F>(self, f: F) -> Self where F: FnMut(T) -> T;
27-
}
28-
29-
impl<T> MoveMap<T> for Vec<T> {
30-
fn move_map<F>(mut self, mut f: F) -> Vec<T>
31-
where F: FnMut(T) -> T
32-
{
33-
for p in &mut self {
34-
unsafe {
35-
// FIXME(#5016) this shouldn't need to zero to be safe.
36-
ptr::write(p, f(ptr::read_and_drop(p)));
37-
}
38-
}
39-
self
40-
}
41-
}
42-
43-
impl<T> MoveMap<T> for OwnedSlice<T> {
44-
fn move_map<F>(self, f: F) -> OwnedSlice<T>
45-
where F: FnMut(T) -> T
46-
{
47-
OwnedSlice::from_vec(self.into_vec().move_map(f))
48-
}
49-
}
23+
use syntax::util::move_map::MoveMap;
5024

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

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

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

503477
pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
504-
l.map(|Local { id, pat, ty, init, span }| {
478+
l.map(|Local { id, pat, ty, init, span, attrs }| {
505479
Local {
506480
id: fld.new_id(id),
507481
ty: ty.map(|t| fld.fold_ty(t)),
508482
pat: fld.fold_pat(pat),
509483
init: init.map(|e| fld.fold_expr(e)),
510484
span: fld.new_span(span),
485+
attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, fld)),
511486
}
512487
})
513488
}
@@ -769,7 +744,7 @@ pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
769744
b.map(|Block { id, stmts, expr, rules, span }| {
770745
Block {
771746
id: folder.new_id(id),
772-
stmts: stmts.into_iter().map(|s| folder.fold_stmt(s)).collect(),
747+
stmts: stmts.move_map(|s| folder.fold_stmt(s)),
773748
expr: expr.map(|x| folder.fold_expr(x)),
774749
rules: rules,
775750
span: folder.new_span(span),
@@ -816,9 +791,8 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
816791
ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
817792
}
818793
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
819-
let new_impl_items = impl_items.into_iter()
820-
.map(|item| folder.fold_impl_item(item))
821-
.collect();
794+
let new_impl_items = impl_items
795+
.move_map(|item| folder.fold_impl_item(item));
822796
let ifce = match ifce {
823797
None => None,
824798
Some(ref trait_ref) => {
@@ -834,9 +808,7 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
834808
}
835809
ItemTrait(unsafety, generics, bounds, items) => {
836810
let bounds = folder.fold_bounds(bounds);
837-
let items = items.into_iter()
838-
.map(|item| folder.fold_trait_item(item))
839-
.collect();
811+
let items = items.move_map(|item| folder.fold_trait_item(item));
840812
ItemTrait(unsafety, folder.fold_generics(generics), bounds, items)
841813
}
842814
}
@@ -892,7 +864,7 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T) -> P<ImplI
892864
pub fn noop_fold_mod<T: Folder>(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod {
893865
Mod {
894866
inner: folder.new_span(inner),
895-
item_ids: item_ids.into_iter().map(|x| folder.fold_item_id(x)).collect(),
867+
item_ids: item_ids.move_map(|x| folder.fold_item_id(x)),
896868
}
897869
}
898870

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

1051-
pub fn noop_fold_expr<T: Folder>(Expr { id, node, span }: Expr, folder: &mut T) -> Expr {
1023+
pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr {
10521024
Expr {
10531025
id: folder.new_id(id),
10541026
node: match node {
@@ -1171,6 +1143,7 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span }: Expr, folder: &mut T)
11711143
}
11721144
},
11731145
span: folder.new_span(span),
1146+
attrs: attrs.map_thin_attrs(|attrs| fold_attrs(attrs, folder)),
11741147
}
11751148
}
11761149

src/librustc_front/hir.rs

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId};
4141
use syntax::abi::Abi;
4242
use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
4343
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, CrateConfig};
44+
use syntax::attr::ThinAttributes;
4445
use syntax::owned_slice::OwnedSlice;
4546
use syntax::parse::token::InternedString;
4647
use syntax::ptr::P;
@@ -558,6 +559,7 @@ pub struct Local {
558559
pub init: Option<P<Expr>>,
559560
pub id: NodeId,
560561
pub span: Span,
562+
pub attrs: ThinAttributes,
561563
}
562564

563565
pub type Decl = Spanned<Decl_>;
@@ -609,6 +611,7 @@ pub struct Expr {
609611
pub id: NodeId,
610612
pub node: Expr_,
611613
pub span: Span,
614+
pub attrs: ThinAttributes,
612615
}
613616

614617
impl fmt::Debug for Expr {

src/librustc_front/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#![feature(slice_patterns)]
3636
#![feature(staged_api)]
3737
#![feature(str_char)]
38-
#![feature(filling_drop)]
3938

4039
extern crate serialize;
4140
#[macro_use]

0 commit comments

Comments
 (0)