diff options
Diffstat (limited to 'compiler/rustc_expand/src/config.rs')
| -rw-r--r-- | compiler/rustc_expand/src/config.rs | 178 |
1 files changed, 103 insertions, 75 deletions
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 1b123520961..5fa7ffd554e 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -171,7 +171,7 @@ fn get_features( } if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() { - if allowed.iter().all(|f| name.as_str() != *f) { + if allowed.iter().all(|f| name.as_str() != f) { struct_span_err!( span_handler, mi.span(), @@ -238,7 +238,7 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> { + pub fn configure<T: AstLike>(&self, mut node: T) -> Option<T> { self.process_cfg_attrs(&mut node); if self.in_cfg(node.attrs()) { self.try_configure_tokens(&mut node); @@ -248,7 +248,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) { + fn try_configure_tokens<T: AstLike>(&self, node: &mut T) { if self.config_tokens { if let Some(Some(tokens)) = node.tokens_mut() { let attr_annotated_tokens = tokens.create_token_stream(); @@ -257,10 +257,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_krate_attrs( - &mut self, - mut attrs: Vec<ast::Attribute>, - ) -> Option<Vec<ast::Attribute>> { + fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); if self.in_cfg(&attrs) { Some(attrs) } else { None } } @@ -269,7 +266,7 @@ impl<'a> StripUnconfigured<'a> { /// This is only used during the invocation of `derive` proc-macros, /// which require that we cfg-expand their entire input. /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method - fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { + fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream { fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool { stream.0.iter().all(|(tree, _spacing)| match tree { AttrAnnotatedTokenTree::Attributes(_) => false, @@ -325,12 +322,16 @@ impl<'a> StripUnconfigured<'a> { /// Gives compiler warnings if any `cfg_attr` does not contain any /// attributes and is in the original source code. Gives compiler errors if /// the syntax of any `cfg_attr` is incorrect. - fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) { + fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) { node.visit_attrs(|attrs| { attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); }); } + fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> { + if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] } + } + /// Parse and expand a single `cfg_attr` attribute into a list of attributes /// when the configuration predicate is true, or otherwise expand into an /// empty list of attributes. @@ -338,11 +339,7 @@ impl<'a> StripUnconfigured<'a> { /// Gives a compiler warning when the `cfg_attr` contains no attributes and /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> { - if !attr.has_name(sym::cfg_attr) { - return vec![attr]; - } - + crate fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> { let (cfg_predicate, expanded_attrs) = match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) { None => return vec![], @@ -351,78 +348,109 @@ impl<'a> StripUnconfigured<'a> { // Lint on zero attributes in source. if expanded_attrs.is_empty() { - return vec![attr]; + self.sess.parse_sess.buffer_lint( + rustc_lint_defs::builtin::UNUSED_ATTRIBUTES, + attr.span, + ast::CRATE_NODE_ID, + "`#[cfg_attr]` does not expand to any attributes", + ); } if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) { return vec![]; } - // We call `process_cfg_attr` recursively in case there's a - // `cfg_attr` inside of another `cfg_attr`. E.g. - // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. - expanded_attrs - .into_iter() - .flat_map(|(item, span)| { - let orig_tokens = attr.tokens().to_tokenstream(); - - // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` - // and producing an attribute of the form `#[attr]`. We - // have captured tokens for `attr` itself, but we need to - // synthesize tokens for the wrapper `#` and `[]`, which - // we do below. - - // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token - // for `attr` when we expand it to `#[attr]` - let mut orig_trees = orig_tokens.trees(); - let pound_token = match orig_trees.next().unwrap() { - TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token, - _ => panic!("Bad tokens for attribute {:?}", attr), - }; - let pound_span = pound_token.span; - - let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)]; - if attr.style == AttrStyle::Inner { - // For inner attributes, we do the same thing for the `!` in `#![some_attr]` - let bang_token = match orig_trees.next().unwrap() { - TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token, - _ => panic!("Bad tokens for attribute {:?}", attr), - }; - trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone)); - } - // We don't really have a good span to use for the syntheized `[]` - // in `#[attr]`, so just use the span of the `#` token. - let bracket_group = AttrAnnotatedTokenTree::Delimited( - DelimSpan::from_single(pound_span), - DelimToken::Bracket, - item.tokens - .as_ref() - .unwrap_or_else(|| panic!("Missing tokens for {:?}", item)) - .create_token_stream(), - ); - trees.push((bracket_group, Spacing::Alone)); - let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees))); - self.process_cfg_attr(attr::mk_attr_from_item(item, tokens, attr.style, span)) - }) - .collect() + if recursive { + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs + .into_iter() + .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item))) + .collect() + } else { + expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect() + } + } + + fn expand_cfg_attr_item( + &self, + attr: &Attribute, + (item, item_span): (ast::AttrItem, Span), + ) -> Attribute { + let orig_tokens = attr.tokens().to_tokenstream(); + + // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` + // and producing an attribute of the form `#[attr]`. We + // have captured tokens for `attr` itself, but we need to + // synthesize tokens for the wrapper `#` and `[]`, which + // we do below. + + // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token + // for `attr` when we expand it to `#[attr]` + let mut orig_trees = orig_tokens.trees(); + let pound_token = match orig_trees.next().unwrap() { + TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token, + _ => panic!("Bad tokens for attribute {:?}", attr), + }; + let pound_span = pound_token.span; + + let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)]; + if attr.style == AttrStyle::Inner { + // For inner attributes, we do the same thing for the `!` in `#![some_attr]` + let bang_token = match orig_trees.next().unwrap() { + TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token, + _ => panic!("Bad tokens for attribute {:?}", attr), + }; + trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone)); + } + // We don't really have a good span to use for the syntheized `[]` + // in `#[attr]`, so just use the span of the `#` token. + let bracket_group = AttrAnnotatedTokenTree::Delimited( + DelimSpan::from_single(pound_span), + DelimToken::Bracket, + item.tokens + .as_ref() + .unwrap_or_else(|| panic!("Missing tokens for {:?}", item)) + .create_token_stream(), + ); + trees.push((bracket_group, Spacing::Alone)); + let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees))); + let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span); + if attr.has_name(sym::crate_type) { + self.sess.parse_sess.buffer_lint( + rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, + attr.span, + ast::CRATE_NODE_ID, + "`crate_type` within an `#![cfg_attr] attribute is deprecated`", + ); + } + if attr.has_name(sym::crate_name) { + self.sess.parse_sess.buffer_lint( + rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, + attr.span, + ast::CRATE_NODE_ID, + "`crate_name` within an `#![cfg_attr] attribute is deprecated`", + ); + } + attr } /// Determines if a node with the given attributes should be included in this configuration. fn in_cfg(&self, attrs: &[Attribute]) -> bool { - attrs.iter().all(|attr| { - if !is_cfg(attr) { + attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr)) + } + + crate fn cfg_true(&self, attr: &Attribute) -> bool { + let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { + Ok(meta_item) => meta_item, + Err(mut err) => { + err.emit(); return true; } - let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { - Ok(meta_item) => meta_item, - Err(mut err) => { - err.emit(); - return true; - } - }; - parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| { - attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features) - }) + }; + parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| { + attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features) }) } @@ -444,7 +472,7 @@ impl<'a> StripUnconfigured<'a> { } } - pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) { + pub fn configure_expr(&self, expr: &mut P<ast::Expr>) { for attr in expr.attrs.iter() { self.maybe_emit_expr_attr_err(attr); } |
