Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 95b52d5

Browse files
committedFeb 24, 2025
pretty print hir attributes
1 parent 309b46a commit 95b52d5

File tree

11 files changed

+335
-21
lines changed

11 files changed

+335
-21
lines changed
 

‎Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3263,6 +3263,7 @@ version = "0.0.0"
32633263
dependencies = [
32643264
"rustc_abi",
32653265
"rustc_ast",
3266+
"rustc_ast_pretty",
32663267
"rustc_data_structures",
32673268
"rustc_macros",
32683269
"rustc_serialize",

‎compiler/rustc_attr_data_structures/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2024"
77
# tidy-alphabetical-start
88
rustc_abi = {path = "../rustc_abi"}
99
rustc_ast = {path = "../rustc_ast"}
10+
rustc_ast_pretty = {path = "../rustc_ast_pretty"}
1011
rustc_data_structures = {path = "../rustc_data_structures"}
1112
rustc_macros = {path = "../rustc_macros"}
1213
rustc_serialize = {path = "../rustc_serialize"}

‎compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use rustc_abi::Align;
22
use rustc_ast::token::CommentKind;
33
use rustc_ast::{self as ast, AttrStyle};
4-
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4+
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
55
use rustc_span::hygiene::Transparency;
66
use rustc_span::{Span, Symbol};
77
use thin_vec::ThinVec;
88

9-
use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability};
9+
use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
1010

1111
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
1212
pub enum InlineAttr {
@@ -57,15 +57,15 @@ impl OptimizeAttr {
5757
}
5858
}
5959

60-
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
60+
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
6161
pub enum DiagnosticAttribute {
6262
// tidy-alphabetical-start
6363
DoNotRecommend,
6464
OnUnimplemented,
6565
// tidy-alphabetical-end
6666
}
6767

68-
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic)]
68+
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
6969
pub enum ReprAttr {
7070
ReprInt(IntType),
7171
ReprRust,
@@ -85,13 +85,13 @@ pub enum TransparencyError {
8585
}
8686

8787
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
88-
#[derive(Encodable, Decodable, HashStable_Generic)]
88+
#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
8989
pub enum IntType {
9090
SignedInt(ast::IntTy),
9191
UnsignedInt(ast::UintTy),
9292
}
9393

94-
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
94+
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
9595
pub struct Deprecation {
9696
pub since: DeprecatedSince,
9797
/// The note to issue a reason.
@@ -103,7 +103,7 @@ pub struct Deprecation {
103103
}
104104

105105
/// Release in which an API is deprecated.
106-
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
106+
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
107107
pub enum DeprecatedSince {
108108
RustcVersion(RustcVersion),
109109
/// Deprecated in the future ("to be determined").
@@ -154,7 +154,7 @@ impl Deprecation {
154154
/// happen.
155155
///
156156
/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html)
157-
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
157+
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
158158
pub enum AttributeKind {
159159
// tidy-alphabetical-start
160160
AllowConstFnUnstable(ThinVec<Symbol>),

‎compiler/rustc_attr_data_structures/src/lib.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,142 @@ mod attributes;
1010
mod stability;
1111
mod version;
1212

13+
use std::num::NonZero;
14+
1315
pub use attributes::*;
16+
use rustc_abi::Align;
17+
use rustc_ast::token::CommentKind;
18+
use rustc_ast::{AttrStyle, IntTy, UintTy};
19+
use rustc_ast_pretty::pp::Printer;
20+
use rustc_span::hygiene::Transparency;
21+
use rustc_span::{Span, Symbol};
1422
pub use stability::*;
23+
use thin_vec::ThinVec;
1524
pub use version::*;
1625

1726
/// Requirements for a `StableHashingContext` to be used in this crate.
1827
/// This is a hack to allow using the `HashStable_Generic` derive macro
1928
/// instead of implementing everything in `rustc_middle`.
2029
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
30+
31+
/// This trait is used to print attributes in `rustc_hir_pretty`.
32+
///
33+
/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
34+
/// The output will look a lot like a `Debug` implementation, but fields of several types
35+
/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
36+
/// representation much.
37+
pub trait PrintAttribute {
38+
fn print_something(&self) -> bool;
39+
fn print_attribute(&self, p: &mut Printer);
40+
}
41+
42+
impl<T: PrintAttribute> PrintAttribute for &T {
43+
fn print_something(&self) -> bool {
44+
T::print_something(self)
45+
}
46+
47+
fn print_attribute(&self, p: &mut Printer) {
48+
T::print_attribute(self, p)
49+
}
50+
}
51+
impl<T: PrintAttribute> PrintAttribute for Option<T> {
52+
fn print_something(&self) -> bool {
53+
self.as_ref().is_some_and(|x| x.print_something())
54+
}
55+
fn print_attribute(&self, p: &mut Printer) {
56+
if let Some(i) = self {
57+
T::print_attribute(i, p)
58+
}
59+
}
60+
}
61+
impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
62+
fn print_something(&self) -> bool {
63+
self.is_empty() || self[0].print_something()
64+
}
65+
fn print_attribute(&self, p: &mut Printer) {
66+
let mut last_printed = false;
67+
p.word("[");
68+
for i in self {
69+
if last_printed {
70+
p.word_space(",");
71+
}
72+
i.print_attribute(p);
73+
last_printed = i.print_something();
74+
}
75+
p.word("]");
76+
}
77+
}
78+
macro_rules! print_skip {
79+
($($t: ty),* $(,)?) => {$(
80+
impl PrintAttribute for $t {
81+
fn print_something(&self) -> bool { false }
82+
fn print_attribute(&self, _: &mut Printer) { }
83+
})*
84+
};
85+
}
86+
87+
macro_rules! print_disp {
88+
($($t: ty),* $(,)?) => {$(
89+
impl PrintAttribute for $t {
90+
fn print_something(&self) -> bool { true }
91+
fn print_attribute(&self, p: &mut Printer) {
92+
p.word(format!("{}", self));
93+
}
94+
}
95+
)*};
96+
}
97+
macro_rules! print_debug {
98+
($($t: ty),* $(,)?) => {$(
99+
impl PrintAttribute for $t {
100+
fn print_something(&self) -> bool { true }
101+
fn print_attribute(&self, p: &mut Printer) {
102+
p.word(format!("{:?}", self));
103+
}
104+
}
105+
)*};
106+
}
107+
108+
macro_rules! print_tup {
109+
(num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* };
110+
() => {};
111+
($t: ident $($ts: ident)*) => {
112+
#[allow(non_snake_case, unused)]
113+
impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
114+
fn print_something(&self) -> bool {
115+
let ($t, $($ts),*) = self;
116+
print_tup!(num_print_something $t $($ts)*) != 0
117+
}
118+
119+
fn print_attribute(&self, p: &mut Printer) {
120+
let ($t, $($ts),*) = self;
121+
let parens = print_tup!(num_print_something $t $($ts)*) > 1;
122+
if parens {
123+
p.word("(");
124+
}
125+
126+
let mut printed_anything = $t.print_something();
127+
128+
$t.print_attribute(p);
129+
130+
$(
131+
if printed_anything && $ts.print_something() {
132+
p.word_space(",");
133+
printed_anything = true;
134+
}
135+
$ts.print_attribute(p);
136+
)*
137+
138+
if parens {
139+
p.word(")");
140+
}
141+
}
142+
}
143+
144+
print_tup!($($ts)*);
145+
};
146+
}
147+
148+
print_tup!(A B C D E F G H);
149+
print_skip!(Span, ());
150+
print_disp!(Symbol, u16, bool, NonZero<u32>);
151+
print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);

‎compiler/rustc_attr_data_structures/src/stability.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::num::NonZero;
22

3-
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
3+
use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
44
use rustc_span::{Symbol, sym};
55

6-
use crate::RustcVersion;
6+
use crate::{PrintAttribute, RustcVersion};
77

88
/// The version placeholder that recently stabilized features contain inside the
99
/// `since` field of the `#[stable]` attribute.
@@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
2121
/// - `#[stable]`
2222
/// - `#[unstable]`
2323
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
24-
#[derive(HashStable_Generic)]
24+
#[derive(HashStable_Generic, PrintAttribute)]
2525
pub struct Stability {
2626
pub level: StabilityLevel,
2727
pub feature: Symbol,
@@ -43,7 +43,7 @@ impl Stability {
4343

4444
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
4545
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
46-
#[derive(HashStable_Generic)]
46+
#[derive(HashStable_Generic, PrintAttribute)]
4747
pub struct ConstStability {
4848
pub level: StabilityLevel,
4949
pub feature: Symbol,
@@ -83,7 +83,7 @@ impl ConstStability {
8383
/// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked`
8484
/// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes
8585
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
86-
#[derive(HashStable_Generic)]
86+
#[derive(HashStable_Generic, PrintAttribute)]
8787
pub struct PartialConstStability {
8888
pub level: StabilityLevel,
8989
pub feature: Symbol,
@@ -103,7 +103,7 @@ impl PartialConstStability {
103103

104104
/// The available stability levels.
105105
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
106-
#[derive(HashStable_Generic)]
106+
#[derive(HashStable_Generic, PrintAttribute)]
107107
pub enum StabilityLevel {
108108
/// `#[unstable]`
109109
Unstable {
@@ -145,7 +145,7 @@ pub enum StabilityLevel {
145145

146146
/// Rust release in which a feature is stabilized.
147147
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
148-
#[derive(HashStable_Generic)]
148+
#[derive(HashStable_Generic, PrintAttribute)]
149149
pub enum StableSince {
150150
/// also stores the original symbol for printing
151151
Version(RustcVersion),
@@ -171,7 +171,7 @@ impl StabilityLevel {
171171
}
172172

173173
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
174-
#[derive(HashStable_Generic)]
174+
#[derive(HashStable_Generic, PrintAttribute)]
175175
pub enum UnstableReason {
176176
None,
177177
Default,
@@ -180,7 +180,7 @@ pub enum UnstableReason {
180180

181181
/// Represents the `#[rustc_default_body_unstable]` attribute.
182182
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
183-
#[derive(HashStable_Generic)]
183+
#[derive(HashStable_Generic, PrintAttribute)]
184184
pub struct DefaultBodyStability {
185185
pub level: StabilityLevel,
186186
pub feature: Symbol,

‎compiler/rustc_attr_data_structures/src/version.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
use std::fmt::{self, Display};
22

3-
use rustc_macros::{Decodable, Encodable, HashStable_Generic, current_rustc_version};
3+
use rustc_macros::{
4+
Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
5+
};
6+
7+
use crate::PrintAttribute;
48

59
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
6-
#[derive(HashStable_Generic)]
10+
#[derive(HashStable_Generic, PrintAttribute)]
711
pub struct RustcVersion {
812
pub major: u16,
913
pub minor: u16,

‎compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
1616
use rustc_ast_pretty::pp::{self, Breaks};
1717
use rustc_ast_pretty::pprust::state::MacHeader;
1818
use rustc_ast_pretty::pprust::{Comments, PrintState};
19-
use rustc_attr_parsing::AttributeKind;
19+
use rustc_attr_parsing::{AttributeKind, PrintAttribute};
2020
use rustc_hir::{
2121
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
2222
HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
@@ -117,7 +117,12 @@ impl<'a> State<'a> {
117117
));
118118
self.hardbreak()
119119
}
120-
_ => unimplemented!("pretty print parsed attributes"),
120+
hir::Attribute::Parsed(pa) => {
121+
self.word("#[attr=\"");
122+
pa.print_attribute(self);
123+
self.word("\")]");
124+
self.hardbreak()
125+
}
121126
}
122127
}
123128

‎compiler/rustc_macros/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod diagnostics;
1717
mod extension;
1818
mod hash_stable;
1919
mod lift;
20+
mod print_attribute;
2021
mod query;
2122
mod serialize;
2223
mod symbols;
@@ -175,3 +176,11 @@ decl_derive! {
175176
/// The error type is `u32`.
176177
try_from::try_from_u32
177178
}
179+
decl_derive! {
180+
[PrintAttribute] =>
181+
/// Derives `PrintAttribute` for `AttributeKind`.
182+
/// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in
183+
/// other places. It's deriving something close to `Debug` without printing some extraenous
184+
/// things like spans.
185+
print_attribute::print_attribute
186+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
use proc_macro2::TokenStream;
2+
use quote::{format_ident, quote, quote_spanned};
3+
use syn::spanned::Spanned;
4+
use syn::{Data, Fields, Ident};
5+
use synstructure::Structure;
6+
7+
fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) {
8+
let string_name = name.to_string();
9+
let mut disps = vec![quote! {let mut __printed_anything = false;}];
10+
11+
match fields {
12+
Fields::Named(fields_named) => {
13+
let mut field_names = Vec::new();
14+
15+
for field in &fields_named.named {
16+
let name = field.ident.as_ref().unwrap();
17+
let string_name = name.to_string();
18+
disps.push(quote! {
19+
if __printed_anything && #name.print_something() {
20+
__p.word_space(",");
21+
__printed_anything = true;
22+
}
23+
__p.word(#string_name);
24+
__p.word_space(":");
25+
#name.print_attribute(__p);
26+
});
27+
field_names.push(name);
28+
}
29+
30+
(
31+
quote! { {#(#field_names),*} },
32+
quote! {
33+
__p.word(#string_name);
34+
if true #(&& !#field_names.print_something())* {
35+
return;
36+
}
37+
38+
__p.word("{");
39+
#(#disps)*
40+
__p.word("}");
41+
},
42+
quote! { true },
43+
)
44+
}
45+
Fields::Unnamed(fields_unnamed) => {
46+
let mut field_names = Vec::new();
47+
48+
for idx in 0..fields_unnamed.unnamed.len() {
49+
let name = format_ident!("f{idx}");
50+
disps.push(quote! {
51+
if __printed_anything && #name.print_something() {
52+
__p.word_space(",");
53+
__printed_anything = true;
54+
}
55+
#name.print_attribute(__p);
56+
});
57+
field_names.push(name);
58+
}
59+
60+
(
61+
quote! { (#(#field_names),*) },
62+
quote! {
63+
__p.word(#string_name);
64+
65+
if true #(&& !#field_names.print_something())* {
66+
return;
67+
}
68+
69+
__p.word("(");
70+
#(#disps)*
71+
__p.word(")");
72+
},
73+
quote! { true },
74+
)
75+
}
76+
Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }),
77+
}
78+
}
79+
80+
pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
81+
let span_error = |span, message: &str| {
82+
quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
83+
};
84+
85+
// Must be applied to an enum type.
86+
let (code, printed) = match &input.ast().data {
87+
Data::Enum(e) => {
88+
let (arms, printed) = e
89+
.variants
90+
.iter()
91+
.map(|x| {
92+
let ident = &x.ident;
93+
let (pat, code, printed) = print_fields(ident, &x.fields);
94+
95+
(
96+
quote! {
97+
Self::#ident #pat => {#code}
98+
},
99+
quote! {
100+
Self::#ident #pat => {#printed}
101+
},
102+
)
103+
})
104+
.unzip::<_, _, Vec<_>, Vec<_>>();
105+
106+
(
107+
quote! {
108+
match self {
109+
#(#arms)*
110+
}
111+
},
112+
quote! {
113+
match self {
114+
#(#printed)*
115+
}
116+
},
117+
)
118+
}
119+
Data::Struct(s) => {
120+
let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields);
121+
(
122+
quote! {
123+
let Self #pat = self;
124+
#code
125+
},
126+
quote! {
127+
let Self #pat = self;
128+
#printed
129+
},
130+
)
131+
}
132+
Data::Union(u) => {
133+
return span_error(u.union_token.span(), "can't derive PrintAttribute on unions");
134+
}
135+
};
136+
137+
#[allow(keyword_idents_2024)]
138+
input.gen_impl(quote! {
139+
#[allow(unused)]
140+
gen impl PrintAttribute for @Self {
141+
fn print_something(&self) -> bool { #printed }
142+
fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
143+
}
144+
})
145+
}

‎tests/pretty/hir-pretty-attr.pp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[prelude_import]
2+
use ::std::prelude::rust_2015::*;
3+
#[macro_use]
4+
extern crate std;
5+
//@ pretty-compare-only
6+
//@ pretty-mode:hir
7+
//@ pp-exact:hir-pretty-attr.pp
8+
9+
#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")]
10+
struct Example {
11+
}

‎tests/pretty/hir-pretty-attr.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//@ pretty-compare-only
2+
//@ pretty-mode:hir
3+
//@ pp-exact:hir-pretty-attr.pp
4+
5+
#[repr(C, packed(4))]
6+
#[repr(transparent)]
7+
struct Example {}

0 commit comments

Comments
 (0)
Please sign in to comment.