diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 571e840795b5..d4407dbf7be7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3446,6 +3446,8 @@ impl AttrItemKind { /// When adding new early parsed attributes, consider whether they should be pretty printed. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum EarlyParsedAttribute { + CfgTrace(CfgEntry), + CfgAttrTrace, } impl AttrItem { diff --git a/compiler/rustc_ast/src/attr/data_structures.rs b/compiler/rustc_ast/src/attr/data_structures.rs new file mode 100644 index 000000000000..2eab91801cd6 --- /dev/null +++ b/compiler/rustc_ast/src/attr/data_structures.rs @@ -0,0 +1,101 @@ +use std::fmt; + +use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_span::{Span, Symbol}; +use thin_vec::ThinVec; + +use crate::attr::version::RustcVersion; + +#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)] +pub enum CfgEntry { + All(ThinVec, Span), + Any(ThinVec, Span), + Not(Box, Span), + Bool(bool, Span), + NameValue { name: Symbol, value: Option, span: Span }, + Version(Option, Span), +} + +impl CfgEntry { + pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) { + match self { + CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => { + *span = lower_span(*span); + subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span)); + } + CfgEntry::Not(sub, span) => { + *span = lower_span(*span); + sub.lower_spans(lower_span); + } + CfgEntry::Bool(_, span) + | CfgEntry::NameValue { span, .. } + | CfgEntry::Version(_, span) => { + *span = lower_span(*span); + } + } + } + + pub fn span(&self) -> Span { + let (Self::All(_, span) + | Self::Any(_, span) + | Self::Not(_, span) + | Self::Bool(_, span) + | Self::NameValue { span, .. } + | Self::Version(_, span)) = self; + *span + } + + /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. + pub fn is_equivalent_to(&self, other: &Self) -> bool { + match (self, other) { + (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { + a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) + } + (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), + (Self::Bool(a, _), Self::Bool(b, _)) => a == b, + ( + Self::NameValue { name: name1, value: value1, .. }, + Self::NameValue { name: name2, value: value2, .. }, + ) => name1 == name2 && value1 == value2, + (Self::Version(a, _), Self::Version(b, _)) => a == b, + _ => false, + } + } +} + +impl fmt::Display for CfgEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn write_entries( + name: &str, + entries: &[CfgEntry], + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + write!(f, "{name}(")?; + for (nb, entry) in entries.iter().enumerate() { + if nb != 0 { + f.write_str(", ")?; + } + entry.fmt(f)?; + } + f.write_str(")") + } + match self { + Self::All(entries, _) => write_entries("all", entries, f), + Self::Any(entries, _) => write_entries("any", entries, f), + Self::Not(entry, _) => write!(f, "not({entry})"), + Self::Bool(value, _) => write!(f, "{value}"), + Self::NameValue { name, value, .. } => { + match value { + // We use `as_str` and debug display to have characters escaped and `"` + // characters surrounding the string. + Some(value) => write!(f, "{name} = {:?}", value.as_str()), + None => write!(f, "{name}"), + } + } + Self::Version(version, _) => match version { + Some(version) => write!(f, "{version}"), + None => Ok(()), + }, + } + } +} diff --git a/compiler/rustc_hir/src/version.rs b/compiler/rustc_ast/src/attr/version.rs similarity index 75% rename from compiler/rustc_hir/src/version.rs rename to compiler/rustc_ast/src/attr/version.rs index 03182088d4c0..59deee40ae28 100644 --- a/compiler/rustc_hir/src/version.rs +++ b/compiler/rustc_ast/src/attr/version.rs @@ -1,16 +1,10 @@ -use std::borrow::Cow; use std::fmt::{self, Display}; use std::sync::OnceLock; -use rustc_error_messages::{DiagArgValue, IntoDiagArg}; -use rustc_macros::{ - BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, -}; - -use crate::attrs::PrintAttribute; +use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version}; #[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] +#[derive(HashStable_Generic)] pub struct RustcVersion { pub major: u16, pub minor: u16, @@ -47,9 +41,3 @@ impl Display for RustcVersion { write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch) } } - -impl IntoDiagArg for RustcVersion { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(self.to_string())) - } -} diff --git a/compiler/rustc_attr_parsing/src/early_parsed.rs b/compiler/rustc_attr_parsing/src/early_parsed.rs new file mode 100644 index 000000000000..6a33cb38edf9 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/early_parsed.rs @@ -0,0 +1,53 @@ +use rustc_ast::EarlyParsedAttribute; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; + +pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] = + &[&[sym::cfg_trace], &[sym::cfg_attr_trace]]; + +/// This struct contains the state necessary to convert early parsed attributes to hir attributes +/// The only conversion that really happens here is that multiple early parsed attributes are +/// merged into a single hir attribute, representing their combined state. +/// FIXME: We should make this a nice and extendable system if this is going to be used more often +#[derive(Default)] +pub(crate) struct EarlyParsedState { + /// Attribute state for `#[cfg]` trace attributes + cfg_trace: ThinVec<(CfgEntry, Span)>, + + /// Attribute state for `#[cfg_attr]` trace attributes + /// The arguments of these attributes is no longer relevant for any later passes, only their presence. + /// So we discard the arguments here. + cfg_attr_trace: bool, +} + +impl EarlyParsedState { + pub(crate) fn accept_early_parsed_attribute( + &mut self, + attr_span: Span, + lower_span: impl Copy + Fn(Span) -> Span, + parsed: &EarlyParsedAttribute, + ) { + match parsed { + EarlyParsedAttribute::CfgTrace(cfg) => { + let mut cfg = cfg.clone(); + cfg.lower_spans(lower_span); + self.cfg_trace.push((cfg, attr_span)); + } + EarlyParsedAttribute::CfgAttrTrace => { + self.cfg_attr_trace = true; + } + } + } + + pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec) { + if !self.cfg_trace.is_empty() { + attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace))); + } + if self.cfg_attr_trace { + attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace)); + } + } +} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 91596ff0de60..e38fffa6587c 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,7 +2,7 @@ use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; -use rustc_ast::{AttrStyle, NodeId, Safety}; +use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -13,6 +13,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; +use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState}; use crate::parser::{ArgParser, PathParser, RefPathParser}; use crate::session_diagnostics::ParsedDescription; use crate::{Early, Late, OmitDoc, ShouldEmit}; @@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> { normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::>(); let path = AttrPath::from_ast(&normal_attr.item.path, identity); - let args = - ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?; + let args = ArgParser::from_attr_args( + &normal_attr.item.args.unparsed_ref().unwrap(), + &parts, + &sess.psess, + emit_errors, + )?; Self::parse_single_args( sess, attr.span, @@ -263,12 +268,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id: S::Id, target: Target, omit_doc: OmitDoc, - lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { let mut attributes = Vec::new(); let mut attr_paths: Vec> = Vec::new(); + let mut early_parsed_state = EarlyParsedState::default(); for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. @@ -288,6 +293,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { continue; } + let attr_span = lower_span(attr.span); match &attr.kind { ast::AttrKind::DocComment(comment_kind, symbol) => { if omit_doc == OmitDoc::Skip { @@ -297,7 +303,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Sugared(*comment_kind), - span: lower_span(attr.span), + span: attr_span, comment: *symbol, })) } @@ -305,6 +311,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_paths.push(PathParser(&n.item.path)); let attr_path = AttrPath::from_ast(&n.item.path, lower_span); + let args = match &n.item.args { + AttrItemKind::Unparsed(args) => args, + AttrItemKind::Parsed(parsed) => { + early_parsed_state + .accept_early_parsed_attribute(attr_span, lower_span, parsed); + continue; + } + }; + self.check_attribute_safety( &attr_path, lower_span(n.item.span()), @@ -318,7 +333,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { let Some(args) = ArgParser::from_attr_args( - &n.item.args, + args, &parts, &self.sess.psess, self.stage.should_emit(), @@ -351,7 +366,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Parsed(AttributeKind::DocComment { style: attr.style, kind: DocFragmentKind::Raw(nv.value_span), - span: attr.span, + span: attr_span, comment, })); continue; @@ -365,7 +380,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { target_id, emit_lint: &mut emit_lint, }, - attr_span: lower_span(attr.span), + attr_span, inner_span: lower_span(n.item.span()), attr_style: attr.style, parsed_description: ParsedDescription::Attribute, @@ -396,17 +411,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attributes.push(Attribute::Unparsed(Box::new(AttrItem { path: attr_path.clone(), - args: self.lower_attr_args(&n.item.args, lower_span), + args: self + .lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span), id: HashIgnoredAttrId { attr_id: attr.id }, style: attr.style, - span: lower_span(attr.span), + span: attr_span, }))); } } } } - let mut parsed_attributes = Vec::new(); + early_parsed_state.finalize_early_parsed_attributes(&mut attributes); for f in &S::parsers().finalizers { if let Some(attr) = f(&mut FinalizeContext { shared: SharedContext { @@ -417,18 +433,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }, all_attrs: &attr_paths, }) { - parsed_attributes.push(Attribute::Parsed(attr)); + attributes.push(Attribute::Parsed(attr)); } } - attributes.extend(parsed_attributes); - attributes } /// Returns whether there is a parser for an attribute with this name pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().accepters.contains_key(path) + Late::parsers().accepters.contains_key(path) || EARLY_PARSED_ATTRIBUTES.contains(&path) } fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 411b4dd75e66..349e6c234520 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -99,6 +99,7 @@ mod interface; /// like lists or name-value pairs. pub mod parser; +mod early_parsed; mod safety; mod session_diagnostics; mod target_checking; diff --git a/compiler/rustc_attr_parsing/src/safety.rs b/compiler/rustc_attr_parsing/src/safety.rs index 68aeca2bbda9..9fca57f88025 100644 --- a/compiler/rustc_attr_parsing/src/safety.rs +++ b/compiler/rustc_attr_parsing/src/safety.rs @@ -4,7 +4,7 @@ use rustc_hir::AttrPath; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_session::lint::LintId; use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE; -use rustc_span::{Span, sym}; +use rustc_span::Span; use crate::context::Stage; use crate::{AttributeParser, ShouldEmit}; @@ -23,11 +23,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { } let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]); - if let Some(name) = name - && [sym::cfg_trace, sym::cfg_attr_trace].contains(&name) - { - return; - } // FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP` let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 492c845df171..28f711f362bd 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, - NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, + HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ @@ -288,7 +288,9 @@ impl<'a> StripUnconfigured<'a> { pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { // 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 trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); + let mut trace_attr = cfg_attr.clone(); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace)); + let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 8102f8e6dac7..c130d9f59940 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -7,12 +7,16 @@ use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID, - ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, - MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, + DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, + ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, + TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{AttributeParser, Early, EvalConfigResult, ShouldEmit, validate_attr}; +use rustc_attr_parsing::{ + AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry, + parse_cfg, validate_attr, +}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; @@ -2188,21 +2192,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { && !AttributeParser::::is_parsed_attribute(&attr.path()) { let attr_name = attr.name().unwrap(); - // `#[cfg]` and `#[cfg_attr]` are special - they are - // eagerly evaluated. - if attr_name != sym::cfg_trace && attr_name != sym::cfg_attr_trace { - self.cx.sess.psess.buffer_lint( - UNUSED_ATTRIBUTES, - attr.span, - self.cx.current_expansion.lint_node_id, - crate::errors::UnusedBuiltinAttribute { - attr_name, - macro_name: pprust::path_to_string(&call.path), - invoc_span: call.path.span, - attr_span: attr.span, - }, - ); - } + self.cx.sess.psess.buffer_lint( + UNUSED_ATTRIBUTES, + attr.span, + self.cx.current_expansion.lint_node_id, + crate::errors::UnusedBuiltinAttribute { + attr_name, + macro_name: pprust::path_to_string(&call.path), + invoc_span: call.path.span, + attr_span: attr.span, + }, + ); } } } @@ -2213,11 +2213,26 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr: ast::Attribute, pos: usize, ) -> EvalConfigResult { - let res = self.cfg().cfg_true(&attr, ShouldEmit::ErrorsAndLints); + let Some(cfg) = AttributeParser::parse_single( + self.cfg().sess, + &attr, + attr.span, + self.cfg().lint_node_id, + self.cfg().features, + ShouldEmit::ErrorsAndLints, + parse_cfg, + &CFG_TEMPLATE, + ) else { + // Cfg attribute was not parsable, give up + return EvalConfigResult::True; + }; + + let res = eval_config_entry(self.cfg().sess, &cfg); if res.as_bool() { // A trace attribute left in AST in place of the original `cfg` attribute. // It can later be used by lints or other diagnostics. - let trace_attr = attr_into_trace(attr, sym::cfg_trace); + let mut trace_attr = attr_into_trace(attr, sym::cfg_trace); + trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg))); node.visit_attrs(|attrs| attrs.insert(pos, trace_attr)); } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index f418c391ece7..fa8998f0546d 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1,9 +1,9 @@ use std::borrow::Cow; -use std::fmt; use std::path::PathBuf; pub use ReprAttr::*; use rustc_abi::Align; +pub use rustc_ast::attr::data_structures::*; use rustc_ast::token::DocFragmentKind; use rustc_ast::{AttrStyle, ast}; use rustc_data_structures::fx::FxIndexMap; @@ -212,83 +212,6 @@ impl StrippedCfgItem { } } -#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic, PrintAttribute)] -pub enum CfgEntry { - All(ThinVec, Span), - Any(ThinVec, Span), - Not(Box, Span), - Bool(bool, Span), - NameValue { name: Symbol, value: Option, span: Span }, - Version(Option, Span), -} - -impl CfgEntry { - pub fn span(&self) -> Span { - let (Self::All(_, span) - | Self::Any(_, span) - | Self::Not(_, span) - | Self::Bool(_, span) - | Self::NameValue { span, .. } - | Self::Version(_, span)) = self; - *span - } - - /// Same as `PartialEq` but doesn't check spans and ignore order of cfgs. - pub fn is_equivalent_to(&self, other: &Self) -> bool { - match (self, other) { - (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => { - a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b))) - } - (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b), - (Self::Bool(a, _), Self::Bool(b, _)) => a == b, - ( - Self::NameValue { name: name1, value: value1, .. }, - Self::NameValue { name: name2, value: value2, .. }, - ) => name1 == name2 && value1 == value2, - (Self::Version(a, _), Self::Version(b, _)) => a == b, - _ => false, - } - } -} - -impl fmt::Display for CfgEntry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn write_entries( - name: &str, - entries: &[CfgEntry], - f: &mut fmt::Formatter<'_>, - ) -> fmt::Result { - write!(f, "{name}(")?; - for (nb, entry) in entries.iter().enumerate() { - if nb != 0 { - f.write_str(", ")?; - } - entry.fmt(f)?; - } - f.write_str(")") - } - match self { - Self::All(entries, _) => write_entries("all", entries, f), - Self::Any(entries, _) => write_entries("any", entries, f), - Self::Not(entry, _) => write!(f, "not({entry})"), - Self::Bool(value, _) => write!(f, "{value}"), - Self::NameValue { name, value, .. } => { - match value { - // We use `as_str` and debug display to have characters escaped and `"` - // characters surrounding the string. - Some(value) => write!(f, "{name} = {:?}", value.as_str()), - None => write!(f, "{name}"), - } - } - Self::Version(version, _) => match version { - Some(version) => write!(f, "{version}"), - None => Ok(()), - }, - } - } -} - /// Possible values for the `#[linkage]` attribute, allowing to specify the /// linkage type for a `MonoItem`. /// @@ -713,6 +636,12 @@ pub enum AttributeKind { span: Span, }, + /// Represents the trace attribute of `#[cfg_attr]` + CfgAttrTrace, + + /// Represents the trace attribute of `#[cfg]` + CfgTrace(ThinVec<(CfgEntry, Span)>), + /// Represents `#[cfi_encoding]` CfiEncoding { encoding: Symbol }, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 57d2d6c5875e..3efa876ed6a9 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -26,6 +26,8 @@ impl AttributeKind { AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, + CfgAttrTrace => Yes, + CfgTrace(..) => Yes, CfiEncoding { .. } => Yes, Coinductive(..) => No, Cold(..) => No, diff --git a/compiler/rustc_hir/src/attrs/pretty_printing.rs b/compiler/rustc_hir/src/attrs/pretty_printing.rs index f8ac2a547ca8..806f5c4d3ed9 100644 --- a/compiler/rustc_hir/src/attrs/pretty_printing.rs +++ b/compiler/rustc_hir/src/attrs/pretty_printing.rs @@ -2,6 +2,8 @@ use std::num::NonZero; use std::ops::Deref; use rustc_abi::Align; +use rustc_ast::attr::data_structures::CfgEntry; +use rustc_ast::attr::version::RustcVersion; use rustc_ast::token::{CommentKind, DocFragmentKind}; use rustc_ast::{AttrStyle, IntTy, UintTy}; use rustc_ast_pretty::pp::Printer; @@ -182,4 +184,6 @@ print_debug!( Transparency, SanitizerSet, DefId, + RustcVersion, + CfgEntry, ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e13782282891..1a9bc8a2781b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1371,6 +1371,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, + Attribute::Parsed(AttributeKind::CfgTrace(cfgs)) => cfgs[0].1, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 7c9c15c16df4..fa46c0f085a2 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -33,7 +33,6 @@ pub mod pat_util; mod stability; mod stable_hash_impls; mod target; -mod version; pub mod weak_lang_items; #[cfg(test)] @@ -42,9 +41,9 @@ mod tests; #[doc(no_inline)] pub use hir::*; pub use lang_items::{LangItem, LanguageItems}; +pub use rustc_ast::attr::version::*; pub use stability::*; pub use stable_hash_impls::HashStableContext; pub use target::{MethodKind, Target}; -pub use version::*; arena_types!(rustc_arena::declare_arena); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7516460155e7..f1cbb72554d2 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -229,6 +229,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect | AttributeKind::MacroTransparency(_) + | AttributeKind::CfgTrace(..) | AttributeKind::Pointee(..) | AttributeKind::Dummy | AttributeKind::RustcBuiltinMacro { .. } @@ -302,6 +303,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) | AttributeKind::PinV2(..) | AttributeKind::WindowsSubsystem(..) + | AttributeKind::CfgAttrTrace | AttributeKind::ThreadLocal | AttributeKind::CfiEncoding { .. } ) => { /* do nothing */ } @@ -338,8 +340,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::forbid | sym::cfg | sym::cfg_attr - | sym::cfg_trace - | sym::cfg_attr_trace // need to be fixed | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) @@ -1950,12 +1950,10 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) // in where clauses. After that, only `self.check_attributes` should be enough. - const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg_trace, sym::cfg_attr_trace]; let spans = self .tcx .hir_attrs(where_predicate.hir_id) .iter() - .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) // FIXME: We shouldn't need to special-case `doc`! .filter(|attr| { matches!(