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`
This commit is contained in:
commit
a97c36dd2e
30 changed files with 599 additions and 84 deletions
|
@ -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>,
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue