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