Skip to main content

rustc_attr_ir/
lib.rs

1//! Data structures for representing parsed attributes in the Rust compiler.
2//!
3//! For detailed documentation about attribute processing,
4//! see [rustc_attr_parsing](../rustc_attr_parsing/index.html).
5
6// tidy-alphabetical-start
7#![expect(internal_features, reason = "rustdoc_internals, for documenting attributes")]
8#![feature(const_default)]
9#![feature(const_trait_impl)]
10#![feature(default_field_values)]
11#![feature(derive_const)]
12#![feature(exhaustive_patterns)]
13#![feature(rustdoc_internals)]
14#![feature(variant_count)]
15#![recursion_limit = "256"]
16// tidy-alphabetical-end
17
18pub use attr::*;
19pub use data_structures::*;
20pub use encode_cross_crate::EncodeCrossCrate;
21pub use lang_items::*;
22pub use pretty_printing::PrintAttribute;
23pub use stability::*;
24
25mod attr;
26mod canonical_symbols;
27mod data_structures;
28pub mod diagnostic;
29pub mod diagnostic_items;
30mod encode_cross_crate;
31pub mod lang_items;
32mod pretty_printing;
33mod stability;
34pub mod target;
35pub mod weak_lang_items;
36
37/// A trait for types that can provide a list of attributes given a `TyCtxt`.
38///
39/// It is an implementation detail of the [`find_attr!`] macro to be able to accept either a
40/// [`DefId`], [`LocalDefId`], [`OwnerId`], or [`HirId`]. It is defined here with a generic `Tcx`
41/// because this crate can't depend on `rustc_middle`. The concrete implementations are in
42/// `rustc_middle`.
43///
44/// Not to be confused with [`rustc_ast::ast_traits::HasAttrs`].
45///
46/// [`DefId`]: rustc_span::def_id::DefId
47/// [`LocalDefId`]: rustc_span::def_id::LocalDefId
48/// [`OwnerId`]: ../rustc_hir/struct.OwnerId.html
49/// [`HirId`]: ../rustc_hir/struct.HirId.html
50pub trait HasAttrs<'tcx, Tcx> {
51    fn get_attrs(self, tcx: &Tcx) -> &'tcx [crate::Attribute];
52}
53
54/// Finds attributes by pattern matching.
55///
56/// A little like `matches` but for attributes.
57///
58/// Note that this macro accepts several "id" types: [`DefId`], [`LocalDefId`], [`OwnerId`] and
59/// [`HirId`].
60///
61/// # Examples
62///
63/// It is most commonly used to check whether something has an attribute or to get its contents
64/// if it is present:
65/// ```rust,ignore (illustrative)
66/// let is_naked: bool = find_attr!(tcx, def_id, Naked(..));
67///
68/// let is_visible: bool = find_attr!(tcx, def_id, Doc(doc) if doc.hidden.is_none());
69///
70/// let link_name: Option<Symbol> = find_attr!(tcx, def_id, LinkName { name, .. } => *name);
71/// ```
72///
73/// Another common case is finding attributes applied to the root of the current crate.
74/// For that, use the shortcut:
75///
76/// ```rust, ignore (illustrative)
77/// find_attr!(tcx, crate, <pattern>)
78/// ```
79///
80/// If you already have a list of attributes in scope, you can also use that:
81///
82/// ```rust,ignore (illustrative)
83/// let attrs = <list of attributes>;
84///
85/// // finds the repr attribute
86/// if let Some(r) = find_attr!(attrs, Repr(r) => r) {
87///
88/// }
89///
90/// // checks if one has matched
91/// if find_attr!(attrs, Repr(_)) {
92///
93/// }
94/// ```
95///
96/// [`DefId`]: rustc_span::def_id::DefId
97/// [`LocalDefId`]: rustc_span::def_id::LocalDefId
98/// [`OwnerId`]: ../rustc_hir/struct.OwnerId.html
99/// [`HirId`]: ../rustc_hir/struct.HirId.html
100#[macro_export]
101macro_rules! find_attr {
102    ($tcx: expr, crate, $pattern: pat $(if $guard: expr)?) => {
103        $crate::find_attr!($tcx, crate, $pattern $(if $guard)? => ()).is_some()
104    };
105    ($tcx: expr, crate, $pattern: pat $(if $guard: expr)? => $e: expr) => {
106        $crate::find_attr!($tcx.hir_krate_attrs(), $pattern $(if $guard)? => $e)
107    };
108
109    ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)?) => {
110        $crate::find_attr!($tcx, $id, $pattern $(if $guard)? => ()).is_some()
111    };
112
113    ($tcx: expr, $id: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
114        $crate::find_attr!(
115            $crate::HasAttrs::get_attrs($id, &$tcx),
116            $pattern $(if $guard)? => $e
117        )
118    }};
119
120    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
121        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
122    }};
123
124    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
125        'done: {
126            for i in $attributes_list {
127                #[allow(unused_imports)]
128                use $crate::AttributeKind::*;
129                let i: &$crate::Attribute = i;
130                match i {
131                    $crate::Attribute::Parsed($pattern) $(if $guard)? => {
132                        break 'done Some($e);
133                    }
134                    $crate::Attribute::Unparsed(..) => {}
135                    // In lint emitting, there's a specific exception for this warning.
136                    // It's not usually emitted from inside macros from other crates
137                    // (see https://github.com/rust-lang/rust/issues/110613)
138                    // But this one is!
139                    #[deny(unreachable_patterns)]
140                    _ => {}
141                }
142            }
143
144            None
145        }
146    }};
147}
148
149include!("attribute_docs.rs");