Remember names of cfg-ed out items to mention them in diagnostics

`#[cfg]`s are frequently used to gate crate content behind cargo
features. This can lead to very confusing errors when features are
missing. For example, `serde` doesn't have the `derive` feature by
default. Therefore, `serde::Serialize` fails to resolve with a generic
error, even though the macro is present in the docs.

This commit adds a list of all stripped item names to metadata. This is
filled during macro expansion and then, through a fed query, persisted
in metadata. The downstream resolver can then access the metadata to
look at possible candidates for mentioning in the errors.

This slightly increases metadata (800k->809k for the feature-heavy
windows crate), but not enough to really matter.
This commit is contained in:
Nilstrieb
2023-03-10 22:39:14 +01:00
parent 642c92e630
commit a647ba250a
30 changed files with 599 additions and 84 deletions

View File

@@ -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`