]>
Commit | Line | Data |
---|---|---|
60c5eb7d XL |
1 | //! Process the potential `cfg` attributes on a module. |
2 | //! Also determine if the module should be included in this configuration. | |
3 | //! | |
dfeec247 | 4 | //! This module properly belongs in rustc_expand, but for now it's tied into |
60c5eb7d XL |
5 | //! parsing, so we leave it here to avoid complicated out-of-line dependencies. |
6 | //! | |
7 | //! A principled solution to this wrong location would be to implement [#64197]. | |
8 | //! | |
9 | //! [#64197]: https://github.com/rust-lang/rust/issues/64197 | |
10 | ||
11 | use crate::{parse_in, validate_attr}; | |
74b04a01 XL |
12 | use rustc_ast::ast::{self, AttrItem, Attribute, MetaItem}; |
13 | use rustc_ast::attr::HasAttrs; | |
14 | use rustc_ast::mut_visit::*; | |
15 | use rustc_ast::ptr::P; | |
16 | use rustc_ast::util::map_in_place::MapInPlace; | |
17 | use rustc_attr as attr; | |
dfeec247 XL |
18 | use rustc_data_structures::fx::FxHashMap; |
19 | use rustc_errors::{error_code, struct_span_err, Applicability, Handler}; | |
20 | use rustc_feature::{Feature, Features, State as FeatureState}; | |
21 | use rustc_feature::{ | |
22 | ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, | |
23 | }; | |
74b04a01 | 24 | use rustc_session::parse::{feature_err, ParseSess}; |
dfeec247 XL |
25 | use rustc_span::edition::{Edition, ALL_EDITIONS}; |
26 | use rustc_span::symbol::{sym, Symbol}; | |
27 | use rustc_span::{Span, DUMMY_SP}; | |
60c5eb7d | 28 | |
9fa01778 | 29 | use smallvec::SmallVec; |
1a4d82fc | 30 | |
3157f602 XL |
31 | /// A folder that strips out items that do not belong in the current configuration. |
32 | pub struct StripUnconfigured<'a> { | |
3157f602 XL |
33 | pub sess: &'a ParseSess, |
34 | pub features: Option<&'a Features>, | |
1a4d82fc JJ |
35 | } |
36 | ||
dfeec247 XL |
37 | fn get_features( |
38 | span_handler: &Handler, | |
39 | krate_attrs: &[ast::Attribute], | |
40 | crate_edition: Edition, | |
41 | allow_features: &Option<Vec<String>>, | |
42 | ) -> Features { | |
43 | fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { | |
44 | let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed"); | |
45 | err.span_label(span, "feature has been removed"); | |
46 | if let Some(reason) = reason { | |
47 | err.note(reason); | |
48 | } | |
49 | err.emit(); | |
50 | } | |
51 | ||
52 | fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> { | |
53 | ACTIVE_FEATURES.iter().filter(move |feature| { | |
54 | if let Some(feature_edition) = feature.edition { | |
55 | feature_edition <= edition | |
56 | } else { | |
57 | false | |
58 | } | |
59 | }) | |
60 | } | |
61 | ||
62 | let mut features = Features::default(); | |
63 | let mut edition_enabled_features = FxHashMap::default(); | |
64 | ||
65 | for &edition in ALL_EDITIONS { | |
66 | if edition <= crate_edition { | |
67 | // The `crate_edition` implies its respective umbrella feature-gate | |
68 | // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). | |
69 | edition_enabled_features.insert(edition.feature_name(), edition); | |
70 | } | |
71 | } | |
72 | ||
73 | for feature in active_features_up_to(crate_edition) { | |
74 | feature.set(&mut features, DUMMY_SP); | |
75 | edition_enabled_features.insert(feature.name, crate_edition); | |
76 | } | |
77 | ||
78 | // Process the edition umbrella feature-gates first, to ensure | |
79 | // `edition_enabled_features` is completed before it's queried. | |
80 | for attr in krate_attrs { | |
81 | if !attr.check_name(sym::feature) { | |
82 | continue; | |
83 | } | |
84 | ||
85 | let list = match attr.meta_item_list() { | |
86 | Some(list) => list, | |
87 | None => continue, | |
88 | }; | |
89 | ||
90 | for mi in list { | |
91 | if !mi.is_word() { | |
92 | continue; | |
93 | } | |
94 | ||
95 | let name = mi.name_or_empty(); | |
96 | ||
97 | let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); | |
98 | if let Some(edition) = edition { | |
99 | if edition <= crate_edition { | |
100 | continue; | |
101 | } | |
102 | ||
103 | for feature in active_features_up_to(edition) { | |
104 | // FIXME(Manishearth) there is currently no way to set | |
105 | // lib features by edition | |
106 | feature.set(&mut features, DUMMY_SP); | |
107 | edition_enabled_features.insert(feature.name, edition); | |
108 | } | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | for attr in krate_attrs { | |
114 | if !attr.check_name(sym::feature) { | |
115 | continue; | |
116 | } | |
117 | ||
118 | let list = match attr.meta_item_list() { | |
119 | Some(list) => list, | |
120 | None => continue, | |
121 | }; | |
122 | ||
123 | let bad_input = |span| { | |
124 | struct_span_err!(span_handler, span, E0556, "malformed `feature` attribute input") | |
125 | }; | |
126 | ||
127 | for mi in list { | |
128 | let name = match mi.ident() { | |
129 | Some(ident) if mi.is_word() => ident.name, | |
130 | Some(ident) => { | |
131 | bad_input(mi.span()) | |
132 | .span_suggestion( | |
133 | mi.span(), | |
134 | "expected just one word", | |
135 | format!("{}", ident.name), | |
136 | Applicability::MaybeIncorrect, | |
137 | ) | |
138 | .emit(); | |
139 | continue; | |
140 | } | |
141 | None => { | |
142 | bad_input(mi.span()).span_label(mi.span(), "expected just one word").emit(); | |
143 | continue; | |
144 | } | |
145 | }; | |
146 | ||
147 | if let Some(edition) = edition_enabled_features.get(&name) { | |
148 | let msg = | |
149 | &format!("the feature `{}` is included in the Rust {} edition", name, edition); | |
150 | span_handler.struct_span_warn_with_code(mi.span(), msg, error_code!(E0705)).emit(); | |
151 | continue; | |
152 | } | |
153 | ||
154 | if ALL_EDITIONS.iter().any(|e| name == e.feature_name()) { | |
155 | // Handled in the separate loop above. | |
156 | continue; | |
157 | } | |
158 | ||
159 | let removed = REMOVED_FEATURES.iter().find(|f| name == f.name); | |
160 | let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.name); | |
161 | if let Some(Feature { state, .. }) = removed.or(stable_removed) { | |
162 | if let FeatureState::Removed { reason } | FeatureState::Stabilized { reason } = | |
163 | state | |
164 | { | |
165 | feature_removed(span_handler, mi.span(), *reason); | |
166 | continue; | |
167 | } | |
168 | } | |
169 | ||
170 | if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { | |
171 | let since = Some(Symbol::intern(since)); | |
172 | features.declared_lang_features.push((name, mi.span(), since)); | |
173 | continue; | |
174 | } | |
175 | ||
176 | if let Some(allowed) = allow_features.as_ref() { | |
177 | if allowed.iter().find(|&f| name.as_str() == *f).is_none() { | |
178 | struct_span_err!( | |
179 | span_handler, | |
180 | mi.span(), | |
181 | E0725, | |
182 | "the feature `{}` is not in the list of allowed features", | |
183 | name | |
184 | ) | |
185 | .emit(); | |
186 | continue; | |
187 | } | |
188 | } | |
189 | ||
190 | if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { | |
191 | f.set(&mut features, mi.span()); | |
192 | features.declared_lang_features.push((name, mi.span(), None)); | |
193 | continue; | |
194 | } | |
195 | ||
196 | features.declared_lib_features.push((name, mi.span())); | |
197 | } | |
198 | } | |
199 | ||
200 | features | |
201 | } | |
202 | ||
9e0c209e | 203 | // `cfg_attr`-process the crate's attributes and compute the crate's features. |
dfeec247 XL |
204 | pub fn features( |
205 | mut krate: ast::Crate, | |
206 | sess: &ParseSess, | |
207 | edition: Edition, | |
208 | allow_features: &Option<Vec<String>>, | |
209 | ) -> (ast::Crate, Features) { | |
74b04a01 | 210 | let mut strip_unconfigured = StripUnconfigured { sess, features: None }; |
9e0c209e | 211 | |
74b04a01 XL |
212 | let unconfigured_attrs = krate.attrs.clone(); |
213 | let diag = &sess.span_diagnostic; | |
214 | let err_count = diag.err_count(); | |
215 | let features = match strip_unconfigured.configure(krate.attrs) { | |
216 | None => { | |
217 | // The entire crate is unconfigured. | |
9e0c209e SL |
218 | krate.attrs = Vec::new(); |
219 | krate.module.items = Vec::new(); | |
74b04a01 | 220 | Features::default() |
9e0c209e | 221 | } |
74b04a01 XL |
222 | Some(attrs) => { |
223 | krate.attrs = attrs; | |
224 | let features = get_features(diag, &krate.attrs, edition, allow_features); | |
225 | if err_count == diag.err_count() { | |
226 | // Avoid reconfiguring malformed `cfg_attr`s. | |
227 | strip_unconfigured.features = Some(&features); | |
228 | strip_unconfigured.configure(unconfigured_attrs); | |
229 | } | |
230 | features | |
9e0c209e | 231 | } |
74b04a01 | 232 | }; |
9e0c209e SL |
233 | (krate, features) |
234 | } | |
235 | ||
e74abb32 | 236 | #[macro_export] |
9e0c209e SL |
237 | macro_rules! configure { |
238 | ($this:ident, $node:ident) => { | |
239 | match $this.configure($node) { | |
240 | Some(node) => node, | |
241 | None => return Default::default(), | |
242 | } | |
dfeec247 | 243 | }; |
9e0c209e SL |
244 | } |
245 | ||
60c5eb7d XL |
246 | const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; |
247 | const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ | |
248 | <https://doc.rust-lang.org/reference/conditional-compilation.html\ | |
249 | #the-cfg_attr-attribute>"; | |
250 | ||
3157f602 | 251 | impl<'a> StripUnconfigured<'a> { |
9fa01778 XL |
252 | pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> { |
253 | self.process_cfg_attrs(&mut node); | |
60c5eb7d | 254 | self.in_cfg(node.attrs()).then_some(node) |
1a4d82fc | 255 | } |
1a4d82fc | 256 | |
0bf4aa26 XL |
257 | /// Parse and expand all `cfg_attr` attributes into a list of attributes |
258 | /// that are within each `cfg_attr` that has a true configuration predicate. | |
259 | /// | |
74b04a01 | 260 | /// Gives compiler warnings if any `cfg_attr` does not contain any |
0bf4aa26 XL |
261 | /// attributes and is in the original source code. Gives compiler errors if |
262 | /// the syntax of any `cfg_attr` is incorrect. | |
9fa01778 XL |
263 | pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: &mut T) { |
264 | node.visit_attrs(|attrs| { | |
265 | attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); | |
266 | }); | |
1a4d82fc | 267 | } |
85aaf69f | 268 | |
0bf4aa26 XL |
269 | /// Parse and expand a single `cfg_attr` attribute into a list of attributes |
270 | /// when the configuration predicate is true, or otherwise expand into an | |
271 | /// empty list of attributes. | |
272 | /// | |
273 | /// Gives a compiler warning when the `cfg_attr` contains no attributes and | |
274 | /// is in the original source file. Gives a compiler error if the syntax of | |
9fa01778 | 275 | /// the attribute is incorrect. |
60c5eb7d XL |
276 | fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> { |
277 | if !attr.has_name(sym::cfg_attr) { | |
0bf4aa26 | 278 | return vec![attr]; |
85aaf69f SL |
279 | } |
280 | ||
60c5eb7d XL |
281 | let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { |
282 | None => return vec![], | |
283 | Some(r) => r, | |
d9579d0f | 284 | }; |
9e0c209e | 285 | |
dc9dc135 XL |
286 | // Lint on zero attributes in source. |
287 | if expanded_attrs.is_empty() { | |
288 | return vec![attr]; | |
0bf4aa26 XL |
289 | } |
290 | ||
dc9dc135 XL |
291 | // At this point we know the attribute is considered used. |
292 | attr::mark_used(&attr); | |
293 | ||
60c5eb7d XL |
294 | if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) { |
295 | return vec![]; | |
296 | } | |
297 | ||
298 | // We call `process_cfg_attr` recursively in case there's a | |
299 | // `cfg_attr` inside of another `cfg_attr`. E.g. | |
300 | // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. | |
301 | expanded_attrs | |
302 | .into_iter() | |
303 | .flat_map(|(item, span)| { | |
304 | let attr = attr::mk_attr_from_item(attr.style, item, span); | |
305 | self.process_cfg_attr(attr) | |
306 | }) | |
0bf4aa26 | 307 | .collect() |
60c5eb7d XL |
308 | } |
309 | ||
310 | fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { | |
311 | match attr.get_normal_item().args { | |
312 | ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => { | |
313 | let msg = "wrong `cfg_attr` delimiters"; | |
314 | validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg); | |
315 | match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { | |
316 | Ok(r) => return Some(r), | |
74b04a01 XL |
317 | Err(mut e) => { |
318 | e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP)) | |
319 | .note(CFG_ATTR_NOTE_REF) | |
320 | .emit(); | |
321 | } | |
60c5eb7d XL |
322 | } |
323 | } | |
324 | _ => self.error_malformed_cfg_attr_missing(attr.span), | |
85aaf69f | 325 | } |
60c5eb7d XL |
326 | None |
327 | } | |
328 | ||
329 | fn error_malformed_cfg_attr_missing(&self, span: Span) { | |
330 | self.sess | |
331 | .span_diagnostic | |
332 | .struct_span_err(span, "malformed `cfg_attr` attribute input") | |
333 | .span_suggestion( | |
334 | span, | |
335 | "missing condition and attribute", | |
336 | CFG_ATTR_GRAMMAR_HELP.to_string(), | |
337 | Applicability::HasPlaceholders, | |
338 | ) | |
339 | .note(CFG_ATTR_NOTE_REF) | |
340 | .emit(); | |
85aaf69f SL |
341 | } |
342 | ||
9fa01778 | 343 | /// Determines if a node with the given attributes should be included in this configuration. |
60c5eb7d | 344 | pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { |
3157f602 | 345 | attrs.iter().all(|attr| { |
8faf50e0 | 346 | if !is_cfg(attr) { |
cc61c64b | 347 | return true; |
8faf50e0 | 348 | } |
74b04a01 XL |
349 | let meta_item = match validate_attr::parse_meta(self.sess, attr) { |
350 | Ok(meta_item) => meta_item, | |
351 | Err(mut err) => { | |
352 | err.emit(); | |
353 | return true; | |
354 | } | |
355 | }; | |
8faf50e0 XL |
356 | let error = |span, msg, suggestion: &str| { |
357 | let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); | |
358 | if !suggestion.is_empty() { | |
9fa01778 | 359 | err.span_suggestion( |
0bf4aa26 XL |
360 | span, |
361 | "expected syntax is", | |
362 | suggestion.into(), | |
363 | Applicability::MaybeIncorrect, | |
364 | ); | |
8faf50e0 XL |
365 | } |
366 | err.emit(); | |
367 | true | |
368 | }; | |
74b04a01 XL |
369 | let span = meta_item.span; |
370 | match meta_item.meta_item_list() { | |
371 | None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), | |
372 | Some([]) => error(span, "`cfg` predicate is not specified", ""), | |
373 | Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), | |
374 | Some([single]) => match single.meta_item() { | |
375 | Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), | |
376 | None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), | |
377 | }, | |
9e0c209e | 378 | } |
3157f602 XL |
379 | }) |
380 | } | |
92a42be0 | 381 | |
0bf4aa26 | 382 | /// Visit attributes on expression and statements (but not attributes on items in blocks). |
60c5eb7d | 383 | fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { |
3157f602 XL |
384 | // flag the offending attributes |
385 | for attr in attrs.iter() { | |
0531ce1d XL |
386 | self.maybe_emit_expr_attr_err(attr); |
387 | } | |
388 | } | |
389 | ||
390 | /// If attributes are not allowed on expressions, emit an error for `attr` | |
60c5eb7d | 391 | pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) { |
0531ce1d | 392 | if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { |
dfeec247 XL |
393 | let mut err = feature_err( |
394 | self.sess, | |
395 | sym::stmt_expr_attributes, | |
396 | attr.span, | |
397 | "attributes on expressions are experimental", | |
398 | ); | |
0531ce1d | 399 | |
60c5eb7d | 400 | if attr.is_doc_comment() { |
0531ce1d | 401 | err.help("`///` is for documentation comments. For a plain comment, use `//`."); |
92a42be0 | 402 | } |
0531ce1d XL |
403 | |
404 | err.emit(); | |
92a42be0 SL |
405 | } |
406 | } | |
92a42be0 | 407 | |
9fa01778 XL |
408 | pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { |
409 | let ast::ForeignMod { abi: _, items } = foreign_mod; | |
410 | items.flat_map_in_place(|item| self.configure(item)); | |
92a42be0 SL |
411 | } |
412 | ||
dc9dc135 XL |
413 | pub fn configure_generic_params(&mut self, params: &mut Vec<ast::GenericParam>) { |
414 | params.flat_map_in_place(|param| self.configure(param)); | |
415 | } | |
416 | ||
9fa01778 | 417 | fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { |
9e0c209e | 418 | match vdata { |
dfeec247 XL |
419 | ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => { |
420 | fields.flat_map_in_place(|field| self.configure(field)) | |
421 | } | |
532ac7d7 | 422 | ast::VariantData::Unit(_) => {} |
9e0c209e SL |
423 | } |
424 | } | |
3157f602 | 425 | |
9fa01778 | 426 | pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) { |
9e0c209e | 427 | match item { |
dfeec247 XL |
428 | ast::ItemKind::Struct(def, _generics) | ast::ItemKind::Union(def, _generics) => { |
429 | self.configure_variant_data(def) | |
430 | } | |
9fa01778 XL |
431 | ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { |
432 | variants.flat_map_in_place(|variant| self.configure(variant)); | |
433 | for variant in variants { | |
e1599b0c | 434 | self.configure_variant_data(&mut variant.data); |
9fa01778 | 435 | } |
3157f602 | 436 | } |
9fa01778 | 437 | _ => {} |
9e0c209e SL |
438 | } |
439 | } | |
3157f602 | 440 | |
9fa01778 | 441 | pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) { |
32a655c1 | 442 | match expr_kind { |
9fa01778 XL |
443 | ast::ExprKind::Match(_m, arms) => { |
444 | arms.flat_map_in_place(|arm| self.configure(arm)); | |
32a655c1 | 445 | } |
9fa01778 XL |
446 | ast::ExprKind::Struct(_path, fields, _base) => { |
447 | fields.flat_map_in_place(|field| self.configure(field)); | |
32a655c1 | 448 | } |
9fa01778 | 449 | _ => {} |
9e0c209e | 450 | } |
92a42be0 SL |
451 | } |
452 | ||
9fa01778 | 453 | pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) { |
9e0c209e | 454 | self.visit_expr_attrs(expr.attrs()); |
3157f602 XL |
455 | |
456 | // If an expr is valid to cfg away it will have been removed by the | |
457 | // outer stmt or expression folder before descending in here. | |
458 | // Anything else is always required, and thus has to error out | |
459 | // in case of a cfg attr. | |
460 | // | |
9fa01778 XL |
461 | // N.B., this is intentionally not part of the visit_expr() function |
462 | // in order for filter_map_expr() to be able to avoid this check | |
b7449926 | 463 | if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { |
3157f602 XL |
464 | let msg = "removing an expression is not supported in this position"; |
465 | self.sess.span_diagnostic.span_err(attr.span, msg); | |
92a42be0 | 466 | } |
3157f602 | 467 | |
9e0c209e | 468 | self.process_cfg_attrs(expr) |
92a42be0 SL |
469 | } |
470 | ||
9fa01778 | 471 | pub fn configure_pat(&mut self, pat: &mut P<ast::Pat>) { |
e74abb32 | 472 | if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { |
9fa01778 XL |
473 | fields.flat_map_in_place(|field| self.configure(field)); |
474 | } | |
32a655c1 | 475 | } |
83c7162d | 476 | |
dc9dc135 XL |
477 | pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { |
478 | fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); | |
83c7162d | 479 | } |
9e0c209e | 480 | } |
92a42be0 | 481 | |
9fa01778 XL |
482 | impl<'a> MutVisitor for StripUnconfigured<'a> { |
483 | fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { | |
484 | self.configure_foreign_mod(foreign_mod); | |
485 | noop_visit_foreign_mod(foreign_mod, self); | |
92a42be0 SL |
486 | } |
487 | ||
9fa01778 XL |
488 | fn visit_item_kind(&mut self, item: &mut ast::ItemKind) { |
489 | self.configure_item_kind(item); | |
490 | noop_visit_item_kind(item, self); | |
9e0c209e SL |
491 | } |
492 | ||
9fa01778 XL |
493 | fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { |
494 | self.configure_expr(expr); | |
e74abb32 | 495 | self.configure_expr_kind(&mut expr.kind); |
9fa01778 | 496 | noop_visit_expr(expr, self); |
9e0c209e SL |
497 | } |
498 | ||
9fa01778 XL |
499 | fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { |
500 | let mut expr = configure!(self, expr); | |
e74abb32 | 501 | self.configure_expr_kind(&mut expr.kind); |
9fa01778 XL |
502 | noop_visit_expr(&mut expr, self); |
503 | Some(expr) | |
9e0c209e SL |
504 | } |
505 | ||
9fa01778 XL |
506 | fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { |
507 | noop_flat_map_stmt(configure!(self, stmt), self) | |
92a42be0 | 508 | } |
92a42be0 | 509 | |
9fa01778 XL |
510 | fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> { |
511 | noop_flat_map_item(configure!(self, item), self) | |
3157f602 | 512 | } |
92a42be0 | 513 | |
74b04a01 | 514 | fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { |
dfeec247 | 515 | noop_flat_map_assoc_item(configure!(self, item), self) |
3157f602 | 516 | } |
92a42be0 | 517 | |
74b04a01 | 518 | fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> { |
dfeec247 | 519 | noop_flat_map_assoc_item(configure!(self, item), self) |
92a42be0 | 520 | } |
3157f602 | 521 | |
9fa01778 | 522 | fn visit_mac(&mut self, _mac: &mut ast::Mac) { |
0731742a | 523 | // Don't configure interpolated AST (cf. issue #34171). |
3157f602 | 524 | // Interpolated AST will get configured once the surrounding tokens are parsed. |
92a42be0 | 525 | } |
32a655c1 | 526 | |
9fa01778 XL |
527 | fn visit_pat(&mut self, pat: &mut P<ast::Pat>) { |
528 | self.configure_pat(pat); | |
529 | noop_visit_pat(pat, self) | |
32a655c1 | 530 | } |
dc9dc135 XL |
531 | |
532 | fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) { | |
533 | self.configure_fn_decl(&mut fn_decl); | |
534 | noop_visit_fn_decl(fn_decl, self); | |
535 | } | |
92a42be0 SL |
536 | } |
537 | ||
60c5eb7d | 538 | fn is_cfg(attr: &Attribute) -> bool { |
48663c56 | 539 | attr.check_name(sym::cfg) |
92a42be0 | 540 | } |
60c5eb7d XL |
541 | |
542 | /// Process the potential `cfg` attributes on a module. | |
543 | /// Also determine if the module should be included in this configuration. | |
74b04a01 | 544 | pub fn process_configure_mod(sess: &ParseSess, cfg_mods: bool, attrs: &mut Vec<Attribute>) -> bool { |
60c5eb7d XL |
545 | // Don't perform gated feature checking. |
546 | let mut strip_unconfigured = StripUnconfigured { sess, features: None }; | |
74b04a01 XL |
547 | strip_unconfigured.process_cfg_attrs(attrs); |
548 | !cfg_mods || strip_unconfigured.in_cfg(&attrs) | |
60c5eb7d | 549 | } |