diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 0491a8c54942..54f3feee96ca 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -19,6 +19,11 @@ use ptr::P; use util::small_vector::SmallVector; +pub trait CfgFolder: fold::Folder { + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool; + fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {} +} + /// A folder that strips out items that do not belong in the current /// configuration. struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { @@ -26,6 +31,19 @@ struct Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { diagnostic: &'a Handler, } +impl<'a, F: FnMut(&[ast::Attribute]) -> bool> CfgFolder for Context<'a, F> { + fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + (self.in_cfg)(attrs) + } + + fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) { + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { + let msg = "removing an expression is not supported in this position"; + self.diagnostic.span_err(attr.span, msg); + } + } +} + // Support conditional compilation by transforming the AST, stripping out // any items that do not belong in the current configuration pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, @@ -48,12 +66,12 @@ pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate, }) } -impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> bool { +impl fold::Folder for T { fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, items: foreign_mod.items.into_iter().filter(|item| { - (self.in_cfg)(&item.attrs) + self.in_cfg(&item.attrs) }).collect(), } } @@ -62,12 +80,12 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> let fold_struct = |this: &mut Self, vdata| match vdata { ast::VariantData::Struct(fields, id) => { ast::VariantData::Struct(fields.into_iter().filter(|m| { - (this.in_cfg)(&m.attrs) + this.in_cfg(&m.attrs) }).collect(), id) } ast::VariantData::Tuple(fields, id) => { ast::VariantData::Tuple(fields.into_iter().filter(|m| { - (this.in_cfg)(&m.attrs) + this.in_cfg(&m.attrs) }).collect(), id) } ast::VariantData::Unit(id) => ast::VariantData::Unit(id) @@ -76,13 +94,13 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> let item = match item { ast::ItemKind::Impl(u, o, a, b, c, impl_items) => { let impl_items = impl_items.into_iter() - .filter(|ii| (self.in_cfg)(&ii.attrs)) + .filter(|ii| self.in_cfg(&ii.attrs)) .collect(); ast::ItemKind::Impl(u, o, a, b, c, impl_items) } ast::ItemKind::Trait(u, a, b, methods) => { let methods = methods.into_iter() - .filter(|ti| (self.in_cfg)(&ti.attrs)) + .filter(|ti| self.in_cfg(&ti.attrs)) .collect(); ast::ItemKind::Trait(u, a, b, methods) } @@ -91,7 +109,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { - if !(self.in_cfg)(&v.node.attrs) { + if !self.in_cfg(&v.node.attrs) { None } else { Some(Spanned { @@ -123,15 +141,12 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> // // NB: This is intentionally not part of the fold_expr() function // in order for fold_opt_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { - self.diagnostic.span_err(attr.span, - "removing an expression is not supported in this position"); - } + self.visit_unconfigurable_expr(&expr); fold_expr(self, expr) } fn fold_opt_expr(&mut self, expr: P) -> Option> { - if (self.in_cfg)(expr.attrs()) { + if self.in_cfg(expr.attrs()) { Some(fold_expr(self, expr)) } else { None @@ -139,7 +154,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { - if (self.in_cfg)(stmt.node.attrs()) { + if self.in_cfg(stmt.node.attrs()) { fold::noop_fold_stmt(stmt, self) } else { SmallVector::zero() @@ -151,7 +166,7 @@ impl<'a, F> fold::Folder for Context<'a, F> where F: FnMut(&[ast::Attribute]) -> } fn fold_item(&mut self, item: P) -> SmallVector> { - if (self.in_cfg)(&item.attrs) { + if self.in_cfg(&item.attrs) { SmallVector::one(item.map(|i| self.fold_item_simple(i))) } else { SmallVector::zero() @@ -170,23 +185,21 @@ pub fn strip_items<'a, F>(diagnostic: &'a Handler, ctxt.fold_crate(krate) } -fn fold_expr(cx: &mut Context, expr: P) -> P where - F: FnMut(&[ast::Attribute]) -> bool -{ +fn fold_expr(folder: &mut F, expr: P) -> P { expr.map(|ast::Expr {id, span, node, attrs}| { fold::noop_fold_expr(ast::Expr { id: id, node: match node { ast::ExprKind::Match(m, arms) => { ast::ExprKind::Match(m, arms.into_iter() - .filter(|a| (cx.in_cfg)(&a.attrs)) + .filter(|a| folder.in_cfg(&a.attrs)) .collect()) } _ => node }, span: span, attrs: attrs, - }, cx) + }, folder) }) }