diff options
| author | Jonathan Dönszelmann <jonathan@donsz.nl> | 2024-10-17 01:14:01 +0200 |
|---|---|---|
| committer | Jonathan Dönszelmann <jonathan@donsz.nl> | 2024-12-15 19:18:46 +0100 |
| commit | d50c0a5480257cbac33b312cb633777f3d2b2483 (patch) | |
| tree | aaf0b2775fb197608969ab9c2c7faab1a05809d2 /compiler/rustc_hir/src | |
| parent | 53b2c7cc95a034467a05a147db1eb4f5666815f8 (diff) | |
| download | rust-d50c0a5480257cbac33b312cb633777f3d2b2483.tar.gz rust-d50c0a5480257cbac33b312cb633777f3d2b2483.zip | |
Add hir::Attribute
Diffstat (limited to 'compiler/rustc_hir/src')
| -rw-r--r-- | compiler/rustc_hir/src/arena.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/hir.rs | 252 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/intravisit.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/lang_items.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_hir/src/stable_hash_impls.rs | 10 |
5 files changed, 265 insertions, 9 deletions
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index f1f624269ae..88c0d223fd3 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -6,7 +6,7 @@ macro_rules! arena_types { $macro!([ // HIR types [] asm_template: rustc_ast::InlineAsmTemplatePiece, - [] attribute: rustc_ast::Attribute, + [] attribute: rustc_hir::Attribute, [] owner_info: rustc_hir::OwnerInfo<'tcx>, [] use_path: rustc_hir::UsePath<'tcx>, [] lit: rustc_hir::Lit, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 957d1b48a27..56dba0c61e2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,10 +1,13 @@ use std::fmt; use rustc_abi::ExternAbi; +// ignore-tidy-filelength +use rustc_ast::attr::AttributeExt; +use rustc_ast::token::CommentKind; use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::{ - self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, - LitKind, TraitObjectSyntax, UintTy, + self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, + IntTy, Label, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, @@ -21,6 +24,7 @@ use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span}; use rustc_target::asm::InlineAsmRegOrRegClass; use smallvec::SmallVec; +use thin_vec::ThinVec; use tracing::debug; use crate::LangItem; @@ -937,6 +941,250 @@ pub struct ParentedNode<'tcx> { pub node: Node<'tcx>, } +/// Arguments passed to an attribute macro. +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub enum AttrArgs { + /// No arguments: `#[attr]`. + Empty, + /// Delimited arguments: `#[attr()/[]/{}]`. + Delimited(DelimArgs), + /// Arguments of a key-value attribute: `#[attr = "value"]`. + Eq { + /// Span of the `=` token. + eq_span: Span, + /// The "value". + expr: MetaItemLit, + }, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub enum AttrKind { + /// A normal attribute. + Normal(Box<AttrItem>), + + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). + /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` + /// variant (which is much less compact and thus more expensive). + DocComment(CommentKind, Symbol), +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct AttrPath { + pub segments: Box<[Ident]>, + pub span: Span, +} + +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +pub struct AttrItem { + pub unsafety: Safety, + // Not lowered to hir::Path because we have no NodeId to resolve to. + pub path: AttrPath, + pub args: AttrArgs, +} + +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct Attribute { + pub kind: AttrKind, + pub id: AttrId, + /// Denotes if the attribute decorates the following construct (outer) + /// or the construct this attribute is contained within (inner). + pub style: AttrStyle, + pub span: Span, +} + +impl Attribute { + pub fn get_normal_item(&self) -> &AttrItem { + match &self.kind { + AttrKind::Normal(normal) => &normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + + pub fn unwrap_normal_item(self) -> AttrItem { + match self.kind { + AttrKind::Normal(normal) => *normal, + AttrKind::DocComment(..) => panic!("unexpected doc comment"), + } + } + + pub fn value_lit(&self) -> Option<&MetaItemLit> { + match &self.kind { + AttrKind::Normal(n) => match n.as_ref() { + AttrItem { args: AttrArgs::Eq { expr, .. }, .. } => Some(expr), + _ => None, + }, + _ => None, + } + } +} + +impl AttributeExt for Attribute { + fn id(&self) -> AttrId { + self.id + } + + fn meta_item_list(&self) -> Option<ThinVec<ast::MetaItemInner>> { + match &self.kind { + AttrKind::Normal(n) => match n.as_ref() { + AttrItem { args: AttrArgs::Delimited(d), .. } => { + ast::MetaItemKind::list_from_tokens(d.tokens.clone()) + } + _ => None, + }, + _ => None, + } + } + + fn value_str(&self) -> Option<Symbol> { + self.value_lit().and_then(|x| x.value_str()) + } + + fn value_span(&self) -> Option<Span> { + self.value_lit().map(|i| i.span) + } + + /// For a single-segment attribute, returns its name; otherwise, returns `None`. + fn ident(&self) -> Option<Ident> { + match &self.kind { + AttrKind::Normal(n) => { + if let [ident] = n.path.segments.as_ref() { + Some(*ident) + } else { + None + } + } + AttrKind::DocComment(..) => None, + } + } + + fn path_matches(&self, name: &[Symbol]) -> bool { + match &self.kind { + AttrKind::Normal(n) => { + n.path.segments.len() == name.len() + && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) + } + AttrKind::DocComment(..) => false, + } + } + + fn is_doc_comment(&self) -> bool { + matches!(self.kind, AttrKind::DocComment(..)) + } + + fn span(&self) -> Span { + self.span + } + + fn is_word(&self) -> bool { + match &self.kind { + AttrKind::Normal(n) => { + matches!(n.args, AttrArgs::Empty) + } + AttrKind::DocComment(..) => false, + } + } + + fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> { + match &self.kind { + AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()), + AttrKind::DocComment(..) => None, + } + } + + fn doc_str(&self) -> Option<Symbol> { + match &self.kind { + AttrKind::DocComment(.., data) => Some(*data), + AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(), + _ => None, + } + } + fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + match &self.kind { + AttrKind::DocComment(kind, data) => Some((*data, *kind)), + AttrKind::Normal(_) if self.name_or_empty() == sym::doc => { + self.value_str().map(|s| (s, CommentKind::Line)) + } + _ => None, + } + } + + fn style(&self) -> AttrStyle { + self.style + } +} + +// FIXME(fn_delegation): use function delegation instead of manually forwarding +impl Attribute { + pub fn id(&self) -> AttrId { + AttributeExt::id(self) + } + + pub fn name_or_empty(&self) -> Symbol { + AttributeExt::name_or_empty(self) + } + + pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { + AttributeExt::meta_item_list(self) + } + + pub fn value_str(&self) -> Option<Symbol> { + AttributeExt::value_str(self) + } + + pub fn value_span(&self) -> Option<Span> { + AttributeExt::value_span(self) + } + + pub fn ident(&self) -> Option<Ident> { + AttributeExt::ident(self) + } + + pub fn path_matches(&self, name: &[Symbol]) -> bool { + AttributeExt::path_matches(self, name) + } + + pub fn is_doc_comment(&self) -> bool { + AttributeExt::is_doc_comment(self) + } + + #[inline] + pub fn has_name(&self, name: Symbol) -> bool { + AttributeExt::has_name(self, name) + } + + pub fn span(&self) -> Span { + AttributeExt::span(self) + } + + pub fn is_word(&self) -> bool { + AttributeExt::is_word(self) + } + + pub fn path(&self) -> SmallVec<[Symbol; 1]> { + AttributeExt::path(self) + } + + pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> { + AttributeExt::ident_path(self) + } + + pub fn doc_str(&self) -> Option<Symbol> { + AttributeExt::doc_str(self) + } + + pub fn is_proc_macro_attr(&self) -> bool { + AttributeExt::is_proc_macro_attr(self) + } + + pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { + AttributeExt::doc_str_and_comment_kind(self) + } + + pub fn style(&self) -> AttrStyle { + AttributeExt::style(self) + } +} + /// Attributes owned by a HIR owner. #[derive(Debug)] pub struct AttributeMap<'tcx> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 6d481f7536a..5ed5a43d522 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -64,8 +64,8 @@ //! This order consistency is required in a few places in rustc, for //! example coroutine inference, and possibly also HIR borrowck. +use rustc_ast::Label; use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; -use rustc_ast::{Attribute, Label}; use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::{Ident, Symbol}; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 15cb331d07a..3684695774e 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -7,7 +7,7 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use rustc_ast as ast; +use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; @@ -153,11 +153,11 @@ impl<CTX> HashStable<CTX> for LangItem { /// Extracts the first `lang = "$name"` out of a list of attributes. /// The `#[panic_handler]` attribute is also extracted out when found. -pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { +pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> { attrs.iter().find_map(|attr| { Some(match attr { - _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span), - _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span), + _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()), + _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()), _ => return None, }) }) diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index fe169e989ec..db0d0fcf3b9 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -2,7 +2,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas use rustc_span::def_id::DefPathHash; use crate::hir::{ - AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, + Attribute, AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, + TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; @@ -12,6 +13,7 @@ use crate::hir_id::{HirId, ItemLocalId}; pub trait HashStableContext: rustc_ast::HashStableContext + rustc_target::HashStableContext { + fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher); } impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId { @@ -113,3 +115,9 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> { opt_hir_hash.unwrap().hash_stable(hcx, hasher) } } + +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Attribute { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + hcx.hash_attr(self, hasher) + } +} |
