rustc_attr_data_structures/
lib.rs

1//! Data structures for representing parsed attributes in the Rust compiler.
2//! For detailed documentation about attribute processing,
3//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html).
4
5// tidy-alphabetical-start
6#![allow(internal_features)]
7#![doc(rust_logo)]
8#![feature(rustdoc_internals)]
9// tidy-alphabetical-end
10
11mod attributes;
12mod stability;
13mod version;
14
15pub mod lints;
16
17use std::num::NonZero;
18
19pub use attributes::*;
20use rustc_abi::Align;
21use rustc_ast::token::CommentKind;
22use rustc_ast::{AttrStyle, IntTy, UintTy};
23use rustc_ast_pretty::pp::Printer;
24use rustc_span::hygiene::Transparency;
25use rustc_span::{Span, Symbol};
26pub use stability::*;
27use thin_vec::ThinVec;
28pub use version::*;
29
30/// Requirements for a `StableHashingContext` to be used in this crate.
31/// This is a hack to allow using the `HashStable_Generic` derive macro
32/// instead of implementing everything in `rustc_middle`.
33pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
34
35/// This trait is used to print attributes in `rustc_hir_pretty`.
36///
37/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
38/// The output will look a lot like a `Debug` implementation, but fields of several types
39/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
40/// representation much.
41pub trait PrintAttribute {
42    /// Whether or not this will render as something meaningful, or if it's skipped
43    /// (which will force the containing struct to also skip printing a comma
44    /// and the field name).
45    fn should_render(&self) -> bool;
46
47    fn print_attribute(&self, p: &mut Printer);
48}
49
50impl<T: PrintAttribute> PrintAttribute for &T {
51    fn should_render(&self) -> bool {
52        T::should_render(self)
53    }
54
55    fn print_attribute(&self, p: &mut Printer) {
56        T::print_attribute(self, p)
57    }
58}
59impl<T: PrintAttribute> PrintAttribute for Option<T> {
60    fn should_render(&self) -> bool {
61        self.as_ref().is_some_and(|x| x.should_render())
62    }
63
64    fn print_attribute(&self, p: &mut Printer) {
65        if let Some(i) = self {
66            T::print_attribute(i, p)
67        }
68    }
69}
70impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
71    fn should_render(&self) -> bool {
72        self.is_empty() || self[0].should_render()
73    }
74
75    fn print_attribute(&self, p: &mut Printer) {
76        let mut last_printed = false;
77        p.word("[");
78        for i in self {
79            if last_printed {
80                p.word_space(",");
81            }
82            i.print_attribute(p);
83            last_printed = i.should_render();
84        }
85        p.word("]");
86    }
87}
88macro_rules! print_skip {
89    ($($t: ty),* $(,)?) => {$(
90        impl PrintAttribute for $t {
91            fn should_render(&self) -> bool { false }
92            fn print_attribute(&self, _: &mut Printer) { }
93        })*
94    };
95}
96
97macro_rules! print_disp {
98    ($($t: ty),* $(,)?) => {$(
99        impl PrintAttribute for $t {
100            fn should_render(&self) -> bool { true }
101            fn print_attribute(&self, p: &mut Printer) {
102                p.word(format!("{}", self));
103            }
104        }
105    )*};
106}
107macro_rules! print_debug {
108    ($($t: ty),* $(,)?) => {$(
109        impl PrintAttribute for $t {
110            fn should_render(&self) -> bool { true }
111            fn print_attribute(&self, p: &mut Printer) {
112                p.word(format!("{:?}", self));
113            }
114        }
115    )*};
116}
117
118macro_rules! print_tup {
119    (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
120    () => {};
121    ($t: ident $($ts: ident)*) => {
122        #[allow(non_snake_case, unused)]
123        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
124            fn should_render(&self) -> bool {
125                let ($t, $($ts),*) = self;
126                print_tup!(num_should_render $t $($ts)*) != 0
127            }
128
129            fn print_attribute(&self, p: &mut Printer) {
130                let ($t, $($ts),*) = self;
131                let parens = print_tup!(num_should_render $t $($ts)*) > 1;
132                if parens {
133                    p.popen();
134                }
135
136                let mut printed_anything = $t.should_render();
137
138                $t.print_attribute(p);
139
140                $(
141                    if $ts.should_render() {
142                        if printed_anything {
143                            p.word_space(",");
144                        }
145                        printed_anything = true;
146                    }
147                    $ts.print_attribute(p);
148                )*
149
150                if parens {
151                    p.pclose();
152                }
153            }
154        }
155
156        print_tup!($($ts)*);
157    };
158}
159
160print_tup!(A B C D E F G H);
161print_skip!(Span, ());
162print_disp!(u16, bool, NonZero<u32>);
163print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
164
165/// Finds attributes in sequences of attributes by pattern matching.
166///
167/// A little like `matches` but for attributes.
168///
169/// ```rust,ignore (illustrative)
170/// // finds the repr attribute
171/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
172///
173/// }
174///
175/// // checks if one has matched
176/// if find_attr!(attrs, AttributeKind::Repr(_)) {
177///
178/// }
179/// ```
180///
181/// Often this requires you to first end up with a list of attributes.
182/// A common way to get those is through `tcx.get_all_attrs(did)`
183#[macro_export]
184macro_rules! find_attr {
185    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
186        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
187    }};
188
189    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
190        'done: {
191            for i in $attributes_list {
192                let i: &rustc_hir::Attribute = i;
193                match i {
194                    rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
195                        break 'done Some($e);
196                    }
197                    _ => {}
198                }
199            }
200
201            None
202        }
203    }};
204}