about summary refs log tree commit diff
path: root/compiler/rustc_expand/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_expand/src/config.rs')
-rw-r--r--compiler/rustc_expand/src/config.rs178
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);
         }