diff options
| author | Jana Dönszelmann <jana@donsz.nl> | 2025-02-09 22:50:03 +0100 |
|---|---|---|
| committer | Jana Dönszelmann <jana@donsz.nl> | 2025-02-24 14:31:19 +0100 |
| commit | 95b52d51eac77be1fcc624c2278dcaafa6989b0b (patch) | |
| tree | a952e5797f050dc9a4cfd4cae3e4483e9e83fe55 | |
| parent | 309b46ad68d15377edd95836796bceb196b2d1b8 (diff) | |
| download | rust-95b52d51eac77be1fcc624c2278dcaafa6989b0b.tar.gz rust-95b52d51eac77be1fcc624c2278dcaafa6989b0b.zip | |
pretty print hir attributes
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/attributes.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/lib.rs | 131 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/stability.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_attr_data_structures/src/version.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_hir_pretty/src/lib.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/lib.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_macros/src/print_attribute.rs | 145 | ||||
| -rw-r--r-- | tests/pretty/hir-pretty-attr.pp | 11 | ||||
| -rw-r--r-- | tests/pretty/hir-pretty-attr.rs | 7 |
11 files changed, 335 insertions, 21 deletions
diff --git a/Cargo.lock b/Cargo.lock index c86351bf78c..fb4cf235c6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3263,6 +3263,7 @@ version = "0.0.0" dependencies = [ "rustc_abi", "rustc_ast", + "rustc_ast_pretty", "rustc_data_structures", "rustc_macros", "rustc_serialize", diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml index ff2212b8df2..b18923c337f 100644 --- a/compiler/rustc_attr_data_structures/Cargo.toml +++ b/compiler/rustc_attr_data_structures/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" # tidy-alphabetical-start rustc_abi = {path = "../rustc_abi"} rustc_ast = {path = "../rustc_ast"} +rustc_ast_pretty = {path = "../rustc_ast_pretty"} rustc_data_structures = {path = "../rustc_data_structures"} rustc_macros = {path = "../rustc_macros"} rustc_serialize = {path = "../rustc_serialize"} diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 3f1edacf9a7..9ac8de0227d 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -1,12 +1,12 @@ use rustc_abi::Align; use rustc_ast::token::CommentKind; use rustc_ast::{self as ast, AttrStyle}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::hygiene::Transparency; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::{DefaultBodyStability, PartialConstStability, RustcVersion, Stability}; +use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum InlineAttr { @@ -57,7 +57,7 @@ impl OptimizeAttr { } } -#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)] pub enum DiagnosticAttribute { // tidy-alphabetical-start DoNotRecommend, @@ -65,7 +65,7 @@ pub enum DiagnosticAttribute { // tidy-alphabetical-end } -#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic)] +#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] pub enum ReprAttr { ReprInt(IntType), ReprRust, @@ -85,13 +85,13 @@ pub enum TransparencyError { } #[derive(Eq, PartialEq, Debug, Copy, Clone)] -#[derive(Encodable, Decodable, HashStable_Generic)] +#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy), } -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub struct Deprecation { pub since: DeprecatedSince, /// The note to issue a reason. @@ -103,7 +103,7 @@ pub struct Deprecation { } /// Release in which an API is deprecated. -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub enum DeprecatedSince { RustcVersion(RustcVersion), /// Deprecated in the future ("to be determined"). @@ -154,7 +154,7 @@ impl Deprecation { /// happen. /// /// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html) -#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind { // tidy-alphabetical-start AllowConstFnUnstable(ThinVec<Symbol>), diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 93d4aa7ddf3..e4bb459e6df 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -10,11 +10,142 @@ mod attributes; mod stability; mod version; +use std::num::NonZero; + pub use attributes::*; +use rustc_abi::Align; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrStyle, IntTy, UintTy}; +use rustc_ast_pretty::pp::Printer; +use rustc_span::hygiene::Transparency; +use rustc_span::{Span, Symbol}; pub use stability::*; +use thin_vec::ThinVec; pub use version::*; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {} + +/// This trait is used to print attributes in `rustc_hir_pretty`. +/// +/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. +/// The output will look a lot like a `Debug` implementation, but fields of several types +/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the +/// representation much. +pub trait PrintAttribute { + fn print_something(&self) -> bool; + fn print_attribute(&self, p: &mut Printer); +} + +impl<T: PrintAttribute> PrintAttribute for &T { + fn print_something(&self) -> bool { + T::print_something(self) + } + + fn print_attribute(&self, p: &mut Printer) { + T::print_attribute(self, p) + } +} +impl<T: PrintAttribute> PrintAttribute for Option<T> { + fn print_something(&self) -> bool { + self.as_ref().is_some_and(|x| x.print_something()) + } + fn print_attribute(&self, p: &mut Printer) { + if let Some(i) = self { + T::print_attribute(i, p) + } + } +} +impl<T: PrintAttribute> PrintAttribute for ThinVec<T> { + fn print_something(&self) -> bool { + self.is_empty() || self[0].print_something() + } + fn print_attribute(&self, p: &mut Printer) { + let mut last_printed = false; + p.word("["); + for i in self { + if last_printed { + p.word_space(","); + } + i.print_attribute(p); + last_printed = i.print_something(); + } + p.word("]"); + } +} +macro_rules! print_skip { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn print_something(&self) -> bool { false } + fn print_attribute(&self, _: &mut Printer) { } + })* + }; +} + +macro_rules! print_disp { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn print_something(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{}", self)); + } + } + )*}; +} +macro_rules! print_debug { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn print_something(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{:?}", self)); + } + } + )*}; +} + +macro_rules! print_tup { + (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* }; + () => {}; + ($t: ident $($ts: ident)*) => { + #[allow(non_snake_case, unused)] + impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { + fn print_something(&self) -> bool { + let ($t, $($ts),*) = self; + print_tup!(num_print_something $t $($ts)*) != 0 + } + + fn print_attribute(&self, p: &mut Printer) { + let ($t, $($ts),*) = self; + let parens = print_tup!(num_print_something $t $($ts)*) > 1; + if parens { + p.word("("); + } + + let mut printed_anything = $t.print_something(); + + $t.print_attribute(p); + + $( + if printed_anything && $ts.print_something() { + p.word_space(","); + printed_anything = true; + } + $ts.print_attribute(p); + )* + + if parens { + p.word(")"); + } + } + } + + print_tup!($($ts)*); + }; +} + +print_tup!(A B C D E F G H); +print_skip!(Span, ()); +print_disp!(Symbol, u16, bool, NonZero<u32>); +print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index c2213fc9ed8..c0ca08a60f8 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -1,9 +1,9 @@ use std::num::NonZero; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::{Symbol, sym}; -use crate::RustcVersion; +use crate::{PrintAttribute, RustcVersion}; /// The version placeholder that recently stabilized features contain inside the /// `since` field of the `#[stable]` attribute. @@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N"); /// - `#[stable]` /// - `#[unstable]` #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, @@ -43,7 +43,7 @@ impl Stability { /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct ConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -83,7 +83,7 @@ impl ConstStability { /// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked` /// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct PartialConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -103,7 +103,7 @@ impl PartialConstStability { /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum StabilityLevel { /// `#[unstable]` Unstable { @@ -145,7 +145,7 @@ pub enum StabilityLevel { /// Rust release in which a feature is stabilized. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum StableSince { /// also stores the original symbol for printing Version(RustcVersion), @@ -171,7 +171,7 @@ impl StabilityLevel { } #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum UnstableReason { None, Default, @@ -180,7 +180,7 @@ pub enum UnstableReason { /// Represents the `#[rustc_default_body_unstable]` attribute. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct DefaultBodyStability { pub level: StabilityLevel, pub feature: Symbol, diff --git a/compiler/rustc_attr_data_structures/src/version.rs b/compiler/rustc_attr_data_structures/src/version.rs index 6be875ad4be..69b0e041d81 100644 --- a/compiler/rustc_attr_data_structures/src/version.rs +++ b/compiler/rustc_attr_data_structures/src/version.rs @@ -1,9 +1,13 @@ use std::fmt::{self, Display}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic, current_rustc_version}; +use rustc_macros::{ + Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, +}; + +use crate::PrintAttribute; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct RustcVersion { pub major: u16, pub minor: u16, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0c18711f6c3..5c7426d76b3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -16,7 +16,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; -use rustc_attr_parsing::AttributeKind; +use rustc_attr_parsing::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, @@ -117,7 +117,12 @@ impl<'a> State<'a> { )); self.hardbreak() } - _ => unimplemented!("pretty print parsed attributes"), + hir::Attribute::Parsed(pa) => { + self.word("#[attr=\""); + pa.print_attribute(self); + self.word("\")]"); + self.hardbreak() + } } } diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 0df674eb4c9..34fc0f00320 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -17,6 +17,7 @@ mod diagnostics; mod extension; mod hash_stable; mod lift; +mod print_attribute; mod query; mod serialize; mod symbols; @@ -175,3 +176,11 @@ decl_derive! { /// The error type is `u32`. try_from::try_from_u32 } +decl_derive! { + [PrintAttribute] => + /// Derives `PrintAttribute` for `AttributeKind`. + /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in + /// other places. It's deriving something close to `Debug` without printing some extraenous + /// things like spans. + print_attribute::print_attribute +} diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs new file mode 100644 index 00000000000..3c6e30b851b --- /dev/null +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -0,0 +1,145 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote, quote_spanned}; +use syn::spanned::Spanned; +use syn::{Data, Fields, Ident}; +use synstructure::Structure; + +fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) { + let string_name = name.to_string(); + let mut disps = vec![quote! {let mut __printed_anything = false;}]; + + match fields { + Fields::Named(fields_named) => { + let mut field_names = Vec::new(); + + for field in &fields_named.named { + let name = field.ident.as_ref().unwrap(); + let string_name = name.to_string(); + disps.push(quote! { + if __printed_anything && #name.print_something() { + __p.word_space(","); + __printed_anything = true; + } + __p.word(#string_name); + __p.word_space(":"); + #name.print_attribute(__p); + }); + field_names.push(name); + } + + ( + quote! { {#(#field_names),*} }, + quote! { + __p.word(#string_name); + if true #(&& !#field_names.print_something())* { + return; + } + + __p.word("{"); + #(#disps)* + __p.word("}"); + }, + quote! { true }, + ) + } + Fields::Unnamed(fields_unnamed) => { + let mut field_names = Vec::new(); + + for idx in 0..fields_unnamed.unnamed.len() { + let name = format_ident!("f{idx}"); + disps.push(quote! { + if __printed_anything && #name.print_something() { + __p.word_space(","); + __printed_anything = true; + } + #name.print_attribute(__p); + }); + field_names.push(name); + } + + ( + quote! { (#(#field_names),*) }, + quote! { + __p.word(#string_name); + + if true #(&& !#field_names.print_something())* { + return; + } + + __p.word("("); + #(#disps)* + __p.word(")"); + }, + quote! { true }, + ) + } + Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }), + } +} + +pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { + let span_error = |span, message: &str| { + quote_spanned! { span => const _: () = ::core::compile_error!(#message); } + }; + + // Must be applied to an enum type. + let (code, printed) = match &input.ast().data { + Data::Enum(e) => { + let (arms, printed) = e + .variants + .iter() + .map(|x| { + let ident = &x.ident; + let (pat, code, printed) = print_fields(ident, &x.fields); + + ( + quote! { + Self::#ident #pat => {#code} + }, + quote! { + Self::#ident #pat => {#printed} + }, + ) + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + ( + quote! { + match self { + #(#arms)* + } + }, + quote! { + match self { + #(#printed)* + } + }, + ) + } + Data::Struct(s) => { + let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields); + ( + quote! { + let Self #pat = self; + #code + }, + quote! { + let Self #pat = self; + #printed + }, + ) + } + Data::Union(u) => { + return span_error(u.union_token.span(), "can't derive PrintAttribute on unions"); + } + }; + + #[allow(keyword_idents_2024)] + input.gen_impl(quote! { + #[allow(unused)] + gen impl PrintAttribute for @Self { + fn print_something(&self) -> bool { #printed } + fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } + } + }) +} diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp new file mode 100644 index 00000000000..586810b0046 --- /dev/null +++ b/tests/pretty/hir-pretty-attr.pp @@ -0,0 +1,11 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-pretty-attr.pp + +#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")] +struct Example { +} diff --git a/tests/pretty/hir-pretty-attr.rs b/tests/pretty/hir-pretty-attr.rs new file mode 100644 index 00000000000..eb5a677024a --- /dev/null +++ b/tests/pretty/hir-pretty-attr.rs @@ -0,0 +1,7 @@ +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-pretty-attr.pp + +#[repr(C, packed(4))] +#[repr(transparent)] +struct Example {} |
