]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/config.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / libsyntax / config.rs
CommitLineData
1a4d82fc
JJ
1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
9e0c209e 11use attr::HasAttrs;
c30ab7b3 12use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
3157f602
XL
13use {fold, attr};
14use ast;
85aaf69f 15use codemap::{Spanned, respan};
9e0c209e 16use parse::ParseSess;
1a4d82fc
JJ
17use ptr::P;
18
19use util::small_vector::SmallVector;
20
3157f602
XL
21/// A folder that strips out items that do not belong in the current configuration.
22pub struct StripUnconfigured<'a> {
3157f602
XL
23 pub should_test: bool,
24 pub sess: &'a ParseSess,
25 pub features: Option<&'a Features>,
1a4d82fc
JJ
26}
27
9e0c209e
SL
28// `cfg_attr`-process the crate's attributes and compute the crate's features.
29pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
30 -> (ast::Crate, Features) {
31 let features;
32 {
33 let mut strip_unconfigured = StripUnconfigured {
9e0c209e
SL
34 should_test: should_test,
35 sess: sess,
36 features: None,
37 };
38
39 let unconfigured_attrs = krate.attrs.clone();
40 let err_count = sess.span_diagnostic.err_count();
41 if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
42 krate.attrs = attrs;
43 } else { // the entire crate is unconfigured
44 krate.attrs = Vec::new();
45 krate.module.items = Vec::new();
46 return (krate, Features::new());
47 }
48
49 features = get_features(&sess.span_diagnostic, &krate.attrs);
50
51 // Avoid reconfiguring malformed `cfg_attr`s
52 if err_count == sess.span_diagnostic.err_count() {
53 strip_unconfigured.features = Some(&features);
54 strip_unconfigured.configure(unconfigured_attrs);
55 }
56 }
57
58 (krate, features)
59}
60
61macro_rules! configure {
62 ($this:ident, $node:ident) => {
63 match $this.configure($node) {
64 Some(node) => node,
65 None => return Default::default(),
66 }
67 }
68}
69
3157f602 70impl<'a> StripUnconfigured<'a> {
9e0c209e 71 pub fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
3157f602
XL
72 let node = self.process_cfg_attrs(node);
73 if self.in_cfg(node.attrs()) { Some(node) } else { None }
1a4d82fc 74 }
1a4d82fc 75
5bcae85e 76 pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: T) -> T {
3157f602
XL
77 node.map_attrs(|attrs| {
78 attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
79 })
1a4d82fc 80 }
85aaf69f 81
3157f602 82 fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
85aaf69f 83 if !attr.check_name("cfg_attr") {
3157f602 84 return Some(attr);
85aaf69f
SL
85 }
86
d9579d0f
AL
87 let attr_list = match attr.meta_item_list() {
88 Some(attr_list) => attr_list,
89 None => {
3157f602
XL
90 let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
91 self.sess.span_diagnostic.span_err(attr.span, msg);
d9579d0f
AL
92 return None;
93 }
94 };
9e0c209e 95
d9579d0f
AL
96 let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
97 (2, Some(cfg), Some(mi)) => (cfg, mi),
85aaf69f 98 _ => {
3157f602
XL
99 let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
100 self.sess.span_diagnostic.span_err(attr.span, msg);
85aaf69f
SL
101 return None;
102 }
103 };
104
9e0c209e
SL
105 use attr::cfg_matches;
106 match (cfg.meta_item(), mi.meta_item()) {
107 (Some(cfg), Some(mi)) =>
c30ab7b3 108 if cfg_matches(&cfg, self.sess, self.features) {
9e0c209e
SL
109 self.process_cfg_attr(respan(mi.span, ast::Attribute_ {
110 id: attr::mk_attr_id(),
111 style: attr.node.style,
112 value: mi.clone(),
113 is_sugared_doc: false,
114 }))
115 } else {
116 None
117 },
118 _ => {
119 let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`";
120 self.sess.span_diagnostic.span_err(attr.span, msg);
121 None
122 }
85aaf69f
SL
123 }
124 }
125
3157f602 126 // Determine if a node with the given attributes should be included in this configuation.
9e0c209e 127 pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
3157f602
XL
128 attrs.iter().all(|attr| {
129 // When not compiling with --test we should not compile the #[test] functions
130 if !self.should_test && is_test_or_bench(attr) {
131 return false;
132 }
92a42be0 133
3157f602
XL
134 let mis = match attr.node.value.node {
135 ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis,
136 _ => return true
137 };
92a42be0 138
3157f602
XL
139 if mis.len() != 1 {
140 self.sess.span_diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
141 return true;
92a42be0
SL
142 }
143
9e0c209e
SL
144 if !mis[0].is_meta_item() {
145 self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal");
146 return true;
147 }
148
c30ab7b3 149 attr::cfg_matches(mis[0].meta_item().unwrap(), self.sess, self.features)
3157f602
XL
150 })
151 }
92a42be0 152
3157f602 153 // Visit attributes on expression and statements (but not attributes on items in blocks).
9e0c209e 154 fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
3157f602
XL
155 // flag the offending attributes
156 for attr in attrs.iter() {
157 if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
c30ab7b3
SL
158 let mut err = feature_err(&self.sess,
159 "stmt_expr_attributes",
160 attr.span,
161 GateIssue::Language,
162 EXPLAIN_STMT_ATTR_SYNTAX);
163 if attr.node.is_sugared_doc {
164 err.help("`///` is for documentation comments. For a plain comment, use `//`.");
165 }
166 err.emit();
92a42be0 167 }
92a42be0
SL
168 }
169 }
92a42be0 170
9e0c209e 171 pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
3157f602
XL
172 ast::ForeignMod {
173 abi: foreign_mod.abi,
9e0c209e 174 items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(),
92a42be0
SL
175 }
176 }
177
9e0c209e
SL
178 fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData {
179 match vdata {
3157f602 180 ast::VariantData::Struct(fields, id) => {
9e0c209e 181 let fields = fields.into_iter().filter_map(|field| self.configure(field));
3157f602
XL
182 ast::VariantData::Struct(fields.collect(), id)
183 }
184 ast::VariantData::Tuple(fields, id) => {
9e0c209e 185 let fields = fields.into_iter().filter_map(|field| self.configure(field));
3157f602
XL
186 ast::VariantData::Tuple(fields.collect(), id)
187 }
188 ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
9e0c209e
SL
189 }
190 }
3157f602 191
9e0c209e
SL
192 pub fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
193 match item {
3157f602 194 ast::ItemKind::Struct(def, generics) => {
9e0c209e
SL
195 ast::ItemKind::Struct(self.configure_variant_data(def), generics)
196 }
197 ast::ItemKind::Union(def, generics) => {
198 ast::ItemKind::Union(self.configure_variant_data(def), generics)
3157f602
XL
199 }
200 ast::ItemKind::Enum(def, generics) => {
201 let variants = def.variants.into_iter().filter_map(|v| {
202 self.configure(v).map(|v| {
203 Spanned {
204 node: ast::Variant_ {
205 name: v.node.name,
206 attrs: v.node.attrs,
9e0c209e 207 data: self.configure_variant_data(v.node.data),
3157f602
XL
208 disr_expr: v.node.disr_expr,
209 },
210 span: v.span
211 }
212 })
213 });
214 ast::ItemKind::Enum(ast::EnumDef {
215 variants: variants.collect(),
216 }, generics)
217 }
218 item => item,
9e0c209e
SL
219 }
220 }
3157f602 221
9e0c209e
SL
222 pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind {
223 if let ast::ExprKind::Match(m, arms) = expr_kind {
224 let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect();
225 ast::ExprKind::Match(m, arms)
226 } else {
227 expr_kind
228 }
92a42be0
SL
229 }
230
9e0c209e
SL
231 pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
232 self.visit_expr_attrs(expr.attrs());
3157f602
XL
233
234 // If an expr is valid to cfg away it will have been removed by the
235 // outer stmt or expression folder before descending in here.
236 // Anything else is always required, and thus has to error out
237 // in case of a cfg attr.
238 //
239 // NB: This is intentionally not part of the fold_expr() function
240 // in order for fold_opt_expr() to be able to avoid this check
241 if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a) || is_test_or_bench(a)) {
242 let msg = "removing an expression is not supported in this position";
243 self.sess.span_diagnostic.span_err(attr.span, msg);
92a42be0 244 }
3157f602 245
9e0c209e 246 self.process_cfg_attrs(expr)
92a42be0
SL
247 }
248
9e0c209e
SL
249 pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
250 self.configure(stmt)
92a42be0 251 }
9e0c209e 252}
92a42be0 253
9e0c209e
SL
254impl<'a> fold::Folder for StripUnconfigured<'a> {
255 fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
256 let foreign_mod = self.configure_foreign_mod(foreign_mod);
257 fold::noop_fold_foreign_mod(foreign_mod, self)
92a42be0
SL
258 }
259
9e0c209e
SL
260 fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
261 let item = self.configure_item_kind(item);
262 fold::noop_fold_item_kind(item, self)
263 }
264
265 fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
266 let mut expr = self.configure_expr(expr).unwrap();
267 expr.node = self.configure_expr_kind(expr.node);
268 P(fold::noop_fold_expr(expr, self))
269 }
270
271 fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
272 let mut expr = configure!(self, expr).unwrap();
273 expr.node = self.configure_expr_kind(expr.node);
274 Some(P(fold::noop_fold_expr(expr, self)))
275 }
276
277 fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
278 match self.configure_stmt(stmt) {
279 Some(stmt) => fold::noop_fold_stmt(stmt, self),
280 None => return SmallVector::zero(),
281 }
92a42be0 282 }
92a42be0 283
3157f602 284 fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
9e0c209e 285 fold::noop_fold_item(configure!(self, item), self)
3157f602 286 }
92a42be0 287
3157f602 288 fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
9e0c209e 289 fold::noop_fold_impl_item(configure!(self, item), self)
3157f602 290 }
92a42be0 291
3157f602 292 fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
9e0c209e 293 fold::noop_fold_trait_item(configure!(self, item), self)
92a42be0 294 }
3157f602 295
9e0c209e 296 fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
3157f602
XL
297 // Don't configure interpolated AST (c.f. #34171).
298 // Interpolated AST will get configured once the surrounding tokens are parsed.
9e0c209e 299 mac
92a42be0
SL
300 }
301}
302
3157f602
XL
303fn is_cfg(attr: &ast::Attribute) -> bool {
304 attr.check_name("cfg")
92a42be0
SL
305}
306
c30ab7b3 307pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
3157f602 308 attr.check_name("test") || attr.check_name("bench")
92a42be0 309}