pretty print hir attributes
This commit is contained in:
parent
309b46ad68
commit
95b52d51ea
11 changed files with 335 additions and 21 deletions
|
@ -3263,6 +3263,7 @@ version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
|
"rustc_ast_pretty",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
|
|
@ -7,6 +7,7 @@ edition = "2024"
|
||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
rustc_abi = {path = "../rustc_abi"}
|
rustc_abi = {path = "../rustc_abi"}
|
||||||
rustc_ast = {path = "../rustc_ast"}
|
rustc_ast = {path = "../rustc_ast"}
|
||||||
|
rustc_ast_pretty = {path = "../rustc_ast_pretty"}
|
||||||
rustc_data_structures = {path = "../rustc_data_structures"}
|
rustc_data_structures = {path = "../rustc_data_structures"}
|
||||||
rustc_macros = {path = "../rustc_macros"}
|
rustc_macros = {path = "../rustc_macros"}
|
||||||
rustc_serialize = {path = "../rustc_serialize"}
|
rustc_serialize = {path = "../rustc_serialize"}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use rustc_abi::Align;
|
use rustc_abi::Align;
|
||||||
use rustc_ast::token::CommentKind;
|
use rustc_ast::token::CommentKind;
|
||||||
use rustc_ast::{self as ast, AttrStyle};
|
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::hygiene::Transparency;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use thin_vec::ThinVec;
|
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)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||||
pub enum InlineAttr {
|
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 {
|
pub enum DiagnosticAttribute {
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
DoNotRecommend,
|
DoNotRecommend,
|
||||||
|
@ -65,7 +65,7 @@ pub enum DiagnosticAttribute {
|
||||||
// tidy-alphabetical-end
|
// 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 {
|
pub enum ReprAttr {
|
||||||
ReprInt(IntType),
|
ReprInt(IntType),
|
||||||
ReprRust,
|
ReprRust,
|
||||||
|
@ -85,13 +85,13 @@ pub enum TransparencyError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
|
||||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
|
||||||
pub enum IntType {
|
pub enum IntType {
|
||||||
SignedInt(ast::IntTy),
|
SignedInt(ast::IntTy),
|
||||||
UnsignedInt(ast::UintTy),
|
UnsignedInt(ast::UintTy),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
|
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
|
||||||
pub struct Deprecation {
|
pub struct Deprecation {
|
||||||
pub since: DeprecatedSince,
|
pub since: DeprecatedSince,
|
||||||
/// The note to issue a reason.
|
/// The note to issue a reason.
|
||||||
|
@ -103,7 +103,7 @@ pub struct Deprecation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release in which an API is deprecated.
|
/// 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 {
|
pub enum DeprecatedSince {
|
||||||
RustcVersion(RustcVersion),
|
RustcVersion(RustcVersion),
|
||||||
/// Deprecated in the future ("to be determined").
|
/// Deprecated in the future ("to be determined").
|
||||||
|
@ -154,7 +154,7 @@ impl Deprecation {
|
||||||
/// happen.
|
/// happen.
|
||||||
///
|
///
|
||||||
/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html)
|
/// 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 {
|
pub enum AttributeKind {
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
AllowConstFnUnstable(ThinVec<Symbol>),
|
AllowConstFnUnstable(ThinVec<Symbol>),
|
||||||
|
|
|
@ -10,11 +10,142 @@ mod attributes;
|
||||||
mod stability;
|
mod stability;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
|
use std::num::NonZero;
|
||||||
|
|
||||||
pub use attributes::*;
|
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::*;
|
pub use stability::*;
|
||||||
|
use thin_vec::ThinVec;
|
||||||
pub use version::*;
|
pub use version::*;
|
||||||
|
|
||||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||||
/// instead of implementing everything in `rustc_middle`.
|
/// instead of implementing everything in `rustc_middle`.
|
||||||
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
|
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);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use std::num::NonZero;
|
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 rustc_span::{Symbol, sym};
|
||||||
|
|
||||||
use crate::RustcVersion;
|
use crate::{PrintAttribute, RustcVersion};
|
||||||
|
|
||||||
/// The version placeholder that recently stabilized features contain inside the
|
/// The version placeholder that recently stabilized features contain inside the
|
||||||
/// `since` field of the `#[stable]` attribute.
|
/// `since` field of the `#[stable]` attribute.
|
||||||
|
@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
|
||||||
/// - `#[stable]`
|
/// - `#[stable]`
|
||||||
/// - `#[unstable]`
|
/// - `#[unstable]`
|
||||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub struct Stability {
|
pub struct Stability {
|
||||||
pub level: StabilityLevel,
|
pub level: StabilityLevel,
|
||||||
pub feature: Symbol,
|
pub feature: Symbol,
|
||||||
|
@ -43,7 +43,7 @@ impl Stability {
|
||||||
|
|
||||||
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
|
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
|
||||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub struct ConstStability {
|
pub struct ConstStability {
|
||||||
pub level: StabilityLevel,
|
pub level: StabilityLevel,
|
||||||
pub feature: Symbol,
|
pub feature: Symbol,
|
||||||
|
@ -83,7 +83,7 @@ impl ConstStability {
|
||||||
/// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked`
|
/// 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
|
/// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes
|
||||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub struct PartialConstStability {
|
pub struct PartialConstStability {
|
||||||
pub level: StabilityLevel,
|
pub level: StabilityLevel,
|
||||||
pub feature: Symbol,
|
pub feature: Symbol,
|
||||||
|
@ -103,7 +103,7 @@ impl PartialConstStability {
|
||||||
|
|
||||||
/// The available stability levels.
|
/// The available stability levels.
|
||||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub enum StabilityLevel {
|
pub enum StabilityLevel {
|
||||||
/// `#[unstable]`
|
/// `#[unstable]`
|
||||||
Unstable {
|
Unstable {
|
||||||
|
@ -145,7 +145,7 @@ pub enum StabilityLevel {
|
||||||
|
|
||||||
/// Rust release in which a feature is stabilized.
|
/// Rust release in which a feature is stabilized.
|
||||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub enum StableSince {
|
pub enum StableSince {
|
||||||
/// also stores the original symbol for printing
|
/// also stores the original symbol for printing
|
||||||
Version(RustcVersion),
|
Version(RustcVersion),
|
||||||
|
@ -171,7 +171,7 @@ impl StabilityLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub enum UnstableReason {
|
pub enum UnstableReason {
|
||||||
None,
|
None,
|
||||||
Default,
|
Default,
|
||||||
|
@ -180,7 +180,7 @@ pub enum UnstableReason {
|
||||||
|
|
||||||
/// Represents the `#[rustc_default_body_unstable]` attribute.
|
/// Represents the `#[rustc_default_body_unstable]` attribute.
|
||||||
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub struct DefaultBodyStability {
|
pub struct DefaultBodyStability {
|
||||||
pub level: StabilityLevel,
|
pub level: StabilityLevel,
|
||||||
pub feature: Symbol,
|
pub feature: Symbol,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
use std::fmt::{self, Display};
|
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(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic, PrintAttribute)]
|
||||||
pub struct RustcVersion {
|
pub struct RustcVersion {
|
||||||
pub major: u16,
|
pub major: u16,
|
||||||
pub minor: u16,
|
pub minor: u16,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
|
||||||
use rustc_ast_pretty::pp::{self, Breaks};
|
use rustc_ast_pretty::pp::{self, Breaks};
|
||||||
use rustc_ast_pretty::pprust::state::MacHeader;
|
use rustc_ast_pretty::pprust::state::MacHeader;
|
||||||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||||
use rustc_attr_parsing::AttributeKind;
|
use rustc_attr_parsing::{AttributeKind, PrintAttribute};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
|
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
|
||||||
HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
|
HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
|
||||||
|
@ -117,7 +117,12 @@ impl<'a> State<'a> {
|
||||||
));
|
));
|
||||||
self.hardbreak()
|
self.hardbreak()
|
||||||
}
|
}
|
||||||
_ => unimplemented!("pretty print parsed attributes"),
|
hir::Attribute::Parsed(pa) => {
|
||||||
|
self.word("#[attr=\"");
|
||||||
|
pa.print_attribute(self);
|
||||||
|
self.word("\")]");
|
||||||
|
self.hardbreak()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ mod diagnostics;
|
||||||
mod extension;
|
mod extension;
|
||||||
mod hash_stable;
|
mod hash_stable;
|
||||||
mod lift;
|
mod lift;
|
||||||
|
mod print_attribute;
|
||||||
mod query;
|
mod query;
|
||||||
mod serialize;
|
mod serialize;
|
||||||
mod symbols;
|
mod symbols;
|
||||||
|
@ -175,3 +176,11 @@ decl_derive! {
|
||||||
/// The error type is `u32`.
|
/// The error type is `u32`.
|
||||||
try_from::try_from_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
|
||||||
|
}
|
||||||
|
|
145
compiler/rustc_macros/src/print_attribute.rs
Normal file
145
compiler/rustc_macros/src/print_attribute.rs
Normal file
|
@ -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 }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
11
tests/pretty/hir-pretty-attr.pp
Normal file
11
tests/pretty/hir-pretty-attr.pp
Normal file
|
@ -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 {
|
||||||
|
}
|
7
tests/pretty/hir-pretty-attr.rs
Normal file
7
tests/pretty/hir-pretty-attr.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
//@ pretty-compare-only
|
||||||
|
//@ pretty-mode:hir
|
||||||
|
//@ pp-exact:hir-pretty-attr.pp
|
||||||
|
|
||||||
|
#[repr(C, packed(4))]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct Example {}
|
Loading…
Add table
Add a link
Reference in a new issue