about summary refs log tree commit diff
path: root/compiler/rustc_expand/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-07 17:38:57 +0000
committerbors <bors@rust-lang.org>2023-06-07 17:38:57 +0000
commita97c36dd2e6f711949fc9b790476e93bd9e6d1f4 (patch)
tree396855263c5ba620f0e10489717dbfd2f09febb2 /compiler/rustc_expand/src
parentb2807b2bf3be9fbed9a0aadc97841c20a1ab5f79 (diff)
parenta647ba250a65b44574830cb71aab5c0403adf31b (diff)
downloadrust-a97c36dd2e6f711949fc9b790476e93bd9e6d1f4.tar.gz
rust-a97c36dd2e6f711949fc9b790476e93bd9e6d1f4.zip
Auto merge of #109005 - Nilstrieb:dont-forgor-too-much-from-cfg, r=petrochenkov
Remember names of `cfg`-ed out items to mention them in diagnostics

# Examples

## `serde::Deserialize` without the `derive` feature (a classic beginner mistake)

I had to slightly modify serde so that it uses explicit re-exports instead of a glob re-export. (Update: a serde PR was merged that adds the manual re-exports)

```
error[E0433]: failed to resolve: could not find `Serialize` in `serde`
   --> src/main.rs:1:17
    |
1   | #[derive(serde::Serialize)]
    |                 ^^^^^^^^^ could not find `Serialize` in `serde`
    |
note: crate `serde` has an item named `Serialize` but it is inactive because its cfg predicate evaluated to false
   --> /home/gh-Nilstrieb/.cargo/registry/src/index.crates.io-6f17d22bba15001f/serde-1.0.160/src/lib.rs:343:1
    |
343 | #[cfg(feature = "serde_derive")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
344 | pub use serde_derive::{Deserialize, Serialize};
    |                                     ^^^^^^^^^
    = note: the item is gated behind the `serde_derive` feature
    = note: see https://doc.rust-lang.org/cargo/reference/features.html for how to activate a crate's feature
```
(the suggestion is not ideal but that's serde's fault)

I already tested the metadata size impact locally by compiling the `windows` crate without any features. `800k`  -> `809k`

r? `@ghost`
Diffstat (limited to 'compiler/rustc_expand/src')
-rw-r--r--compiler/rustc_expand/src/base.rs4
-rw-r--r--compiler/rustc_expand/src/config.rs20
-rw-r--r--compiler/rustc_expand/src/expand.rs49
3 files changed, 61 insertions, 12 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 0d43b30474b..b7c30841983 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -947,6 +947,8 @@ pub trait ResolverExpand {
     /// HIR proc macros items back to their harness items.
     fn declare_proc_macro(&mut self, id: NodeId);
 
+    fn append_stripped_cfg_item(&mut self, parent_node: NodeId, name: Ident, cfg: ast::MetaItem);
+
     /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
     fn registered_tools(&self) -> &RegisteredTools;
 }
@@ -965,7 +967,7 @@ pub trait LintStoreExpand {
 
 type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
 
-#[derive(Clone, Default)]
+#[derive(Debug, Clone, Default)]
 pub struct ModuleData {
     /// Path to the module starting from the crate name, like `my_crate::foo::bar`.
     pub mod_path: Vec<Ident>,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 4ff8e409d88..690f80f6876 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -416,20 +416,28 @@ impl<'a> StripUnconfigured<'a> {
 
     /// 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| !is_cfg(attr) || self.cfg_true(attr))
+        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr).0)
     }
 
-    pub(crate) fn cfg_true(&self, attr: &Attribute) -> bool {
+    pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
         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;
+                return (true, None);
             }
         };
-        parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
-            attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.lint_node_id, self.features)
-        })
+        (
+            parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+                attr::cfg_matches(
+                    &meta_item,
+                    &self.sess.parse_sess,
+                    self.lint_node_id,
+                    self.features,
+                )
+            }),
+            Some(meta_item),
+        )
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ce0093c7d4c..dd8863df195 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1042,6 +1042,12 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     fn expand_cfg_false(&mut self, collector: &mut InvocationCollector<'_, '_>, span: Span) {
         collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
     }
+
+    /// All of the names (items) declared by this node.
+    /// This is an approximation and should only be used for diagnostics.
+    fn declared_names(&self) -> Vec<Ident> {
+        vec![]
+    }
 }
 
 impl InvocationCollectorNode for P<ast::Item> {
@@ -1148,6 +1154,27 @@ impl InvocationCollectorNode for P<ast::Item> {
         collector.cx.current_expansion.module = orig_module;
         res
     }
+    fn declared_names(&self) -> Vec<Ident> {
+        if let ItemKind::Use(ut) = &self.kind {
+            fn collect_use_tree_leaves(ut: &ast::UseTree, idents: &mut Vec<Ident>) {
+                match &ut.kind {
+                    ast::UseTreeKind::Glob => {}
+                    ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
+                    ast::UseTreeKind::Nested(nested) => {
+                        for (ut, _) in nested {
+                            collect_use_tree_leaves(&ut, idents);
+                        }
+                    }
+                }
+            }
+
+            let mut idents = Vec::new();
+            collect_use_tree_leaves(&ut, &mut idents);
+            return idents;
+        }
+
+        vec![self.ident]
+    }
 }
 
 struct TraitItemTag;
@@ -1685,8 +1712,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         node: &mut impl HasAttrs,
         attr: ast::Attribute,
         pos: usize,
-    ) -> bool {
-        let res = self.cfg().cfg_true(&attr);
+    ) -> (bool, Option<ast::MetaItem>) {
+        let (res, meta_item) = self.cfg().cfg_true(&attr);
         if res {
             // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
             // and some tools like rustdoc and clippy rely on that. Find a way to remove them
@@ -1694,7 +1721,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             self.cx.expanded_inert_attrs.mark(&attr);
             node.visit_attrs(|attrs| attrs.insert(pos, attr));
         }
-        res
+
+        (res, meta_item)
     }
 
     fn expand_cfg_attr(&self, node: &mut impl HasAttrs, attr: &ast::Attribute, pos: usize) {
@@ -1715,9 +1743,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
             return match self.take_first_attr(&mut node) {
                 Some((attr, pos, derives)) => match attr.name_or_empty() {
                     sym::cfg => {
-                        if self.expand_cfg_true(&mut node, attr, pos) {
+                        let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
+                        if res {
                             continue;
                         }
+
+                        if let Some(meta_item) = meta_item {
+                            for name in node.declared_names() {
+                                self.cx.resolver.append_stripped_cfg_item(
+                                    self.cx.current_expansion.lint_node_id,
+                                    name,
+                                    meta_item.clone(),
+                                )
+                            }
+                        }
                         Default::default()
                     }
                     sym::cfg_attr => {
@@ -1761,7 +1800,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                 Some((attr, pos, derives)) => match attr.name_or_empty() {
                     sym::cfg => {
                         let span = attr.span;
-                        if self.expand_cfg_true(node, attr, pos) {
+                        if self.expand_cfg_true(node, attr, pos).0 {
                             continue;
                         }