1
Fork 0

expand: Leave traces when expanding cfg_attr attributes

This commit is contained in:
Vadim Petrochenkov 2025-03-14 20:34:43 +03:00
parent 9bad8ac498
commit 9dd4e4cad1
10 changed files with 136 additions and 19 deletions

View file

@ -1,12 +1,15 @@
//! Conditional compilation stripping.
use std::iter;
use rustc_ast::ptr::P;
use rustc_ast::token::{Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::{
AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
};
use rustc_ast::{
self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId,
self as ast, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner,
NodeId, NormalAttr,
};
use rustc_attr_parsing as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
@ -275,10 +278,23 @@ impl<'a> StripUnconfigured<'a> {
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
validate_attr::check_attribute_safety(&self.sess.psess, AttributeSafety::Normal, &cfg_attr);
// A trace attribute left in AST in place of the original `cfg_attr` attribute.
// It can later be used by lints or other diagnostics.
let mut trace_attr = cfg_attr.clone();
match &mut trace_attr.kind {
AttrKind::Normal(normal) => {
let NormalAttr { item, tokens } = &mut **normal;
item.path.segments[0].ident.name = sym::cfg_attr_trace;
// This makes the trace attributes unobservable to token-based proc macros.
*tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::default()));
}
AttrKind::DocComment(..) => unreachable!(),
}
let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
else {
return vec![];
return vec![trace_attr];
};
// Lint on zero attributes in source.
@ -292,22 +308,21 @@ impl<'a> StripUnconfigured<'a> {
}
if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) {
return vec![];
return vec![trace_attr];
}
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
let expanded_attrs = expanded_attrs
.into_iter()
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item)))
.collect()
.flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item)));
iter::once(trace_attr).chain(expanded_attrs).collect()
} else {
expanded_attrs
.into_iter()
.map(|item| self.expand_cfg_attr_item(cfg_attr, item))
.collect()
let expanded_attrs =
expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(cfg_attr, item));
iter::once(trace_attr).chain(expanded_attrs).collect()
}
}