diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3b2dcb3db81db..1207f2f0360f2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -768,12 +768,22 @@ impl Item { .iter() .filter_map(|attr| { if is_json { - if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) { - // rustdoc-json stores this in `Item::deprecation`, so we - // don't want it it `Item::attrs`. - None - } else { - Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)) + match attr { + hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => { + // rustdoc-json stores this in `Item::deprecation`, so we + // don't want it it `Item::attrs`. + None + } + rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr( + .., + )) => { + // We have separate pretty-printing logic for `#[repr(..)]` attributes. + // For example, there are circumstances where `#[repr(transparent)]` + // is applied but should not be publicly shown in rustdoc + // because it isn't public API. + None + } + _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)), } } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { Some( @@ -789,8 +799,7 @@ impl Item { .collect(); // Add #[repr(...)] - if !is_json - && let Some(def_id) = self.def_id() + if let Some(def_id) = self.def_id() && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() { let adt = tcx.adt_def(def_id); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 44e82c7d8b195..137fe4c4c3544 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 42; +pub const FORMAT_VERSION: u32 = 43; /// The root of the emitted JSON blob. /// @@ -120,9 +120,23 @@ pub struct Item { pub docs: Option, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: HashMap, - /// Stringified versions of parsed attributes on this item. - /// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`). - /// Equivalent to the hir pretty-printing of attributes. + /// Attributes on this item. + /// + /// Does not include `#[deprecated]` attributes: see the [`Self::deprecation`] field instead. + /// + /// Some attributes appear in pretty-printed Rust form, regardless of their formatting + /// in the original source code. For example: + /// - `#[non_exhaustive]` and `#[must_use]` are represented as themselves. + /// - `#[no_mangle]` and `#[export_name]` are also represented as themselves. + /// - `#[repr(C)]` and other reprs also appear as themselves, + /// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`. + /// Multiple repr attributes on the same item may be combined into an equivalent single attr. + /// + /// Other attributes may appear debug-printed. For example: + /// - `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`. + /// + /// As an internal implementation detail subject to change, this debug-printing format + /// is currently equivalent to the HIR pretty-printing of parsed attributes. pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, diff --git a/tests/rustdoc-json/attrs/repr_align.rs b/tests/rustdoc-json/attrs/repr_align.rs index 83506737b211a..c6debda7f1c9e 100644 --- a/tests/rustdoc-json/attrs/repr_align.rs +++ b/tests/rustdoc-json/attrs/repr_align.rs @@ -1,6 +1,6 @@ #![no_std] -//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]' #[repr(align(4))] pub struct Aligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_c.rs b/tests/rustdoc-json/attrs/repr_c.rs index 018086b3c1ffd..e6219413f3086 100644 --- a/tests/rustdoc-json/attrs/repr_c.rs +++ b/tests/rustdoc-json/attrs/repr_c.rs @@ -1,16 +1,16 @@ #![no_std] -//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]' #[repr(C)] pub struct ReprCStruct(pub i64); -//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]' #[repr(C)] pub enum ReprCEnum { First, } -//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]' #[repr(C)] pub union ReprCUnion { pub left: i64, diff --git a/tests/rustdoc-json/attrs/repr_combination.rs b/tests/rustdoc-json/attrs/repr_combination.rs index c3ef8becb7791..0e8e2ef0d83e9 100644 --- a/tests/rustdoc-json/attrs/repr_combination.rs +++ b/tests/rustdoc-json/attrs/repr_combination.rs @@ -1,34 +1,35 @@ #![no_std] // Combinations of `#[repr(..)]` attributes. +// Rustdoc JSON emits normalized output, regardless of the original source. -//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]' #[repr(C, i8)] pub enum ReprCI8 { First, } -//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]' #[repr(C)] #[repr(i16)] pub enum SeparateReprCI16 { First, } -//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]' #[repr(usize, C)] pub enum ReversedReprCUsize { First, } -//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]' #[repr(C, packed)] pub struct ReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' #[repr(C)] #[repr(packed(2))] pub struct SeparateReprCPacked { @@ -36,21 +37,21 @@ pub struct SeparateReprCPacked { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]' #[repr(packed(2), C)] pub struct ReversedReprCPacked { a: i8, b: i64, } -//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]' #[repr(C, align(16))] pub struct ReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]' +//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]' #[repr(C)] #[repr(align(2))] pub struct SeparateReprCAlign { @@ -58,20 +59,20 @@ pub struct SeparateReprCAlign { b: i64, } -//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]' +//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]' #[repr(align(2), C)] pub struct ReversedReprCAlign { a: i8, b: i64, } -//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]' +//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' #[repr(C, align(16), isize)] pub enum AlignedExplicitRepr { First, } -//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]' +//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]' #[repr(isize, C, align(16))] pub enum ReorderedAlignedExplicitRepr { First, diff --git a/tests/rustdoc-json/attrs/repr_int_enum.rs b/tests/rustdoc-json/attrs/repr_int_enum.rs index 206cb7835f52c..9b09f341d4fee 100644 --- a/tests/rustdoc-json/attrs/repr_int_enum.rs +++ b/tests/rustdoc-json/attrs/repr_int_enum.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]' +//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]' #[repr(i8)] pub enum I8 { First, } -//@ is "$.index[?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]' #[repr(i32)] pub enum I32 { First, } -//@ is "$.index[?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]' +//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]' #[repr(usize)] pub enum Usize { First, diff --git a/tests/rustdoc-json/attrs/repr_packed.rs b/tests/rustdoc-json/attrs/repr_packed.rs index d4c400f72f811..9f3fd86c4b03c 100644 --- a/tests/rustdoc-json/attrs/repr_packed.rs +++ b/tests/rustdoc-json/attrs/repr_packed.rs @@ -1,16 +1,16 @@ #![no_std] // Note the normalization: -// `#[repr(packed)]` in has the implict "1" in rustdoc JSON. - -//@ is "$.index[?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]' +// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON. +// +//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]' #[repr(packed)] pub struct Packed { a: i8, b: i64, } -//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]' +//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]' #[repr(packed(4))] pub struct PackedAligned { a: i8, diff --git a/tests/rustdoc-json/attrs/repr_transparent.rs b/tests/rustdoc-json/attrs/repr_transparent.rs index 3f57b21dcc52e..1e634ca901dc4 100644 --- a/tests/rustdoc-json/attrs/repr_transparent.rs +++ b/tests/rustdoc-json/attrs/repr_transparent.rs @@ -1,22 +1,37 @@ #![no_std] -// Rustdoc JSON currently includes `#[repr(transparent)]` -// even if the transparency is not part of the public API +// Rustdoc JSON *only* includes `#[repr(transparent)]` +// if the transparency is public API: +// - if a non-1-ZST field exists, it has to be public +// - otherwise, all fields are 1-ZST and at least one of them is public // -// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent +// More info: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent -//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Here, the non-1-ZST field is public. +// We expect `#[repr(transparent)]` in the attributes. +// +//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]' #[repr(transparent)] pub struct Transparent(pub i64); -//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Here the non-1-ZST field isn't public, so the attribute isn't included. +// +//@ has "$.index[?(@.name=='TransparentNonPub')]" +//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '[]' #[repr(transparent)] pub struct TransparentNonPub(i64); -//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Only 1-ZST fields here, and one of them is public. +// We expect `#[repr(transparent)]` in the attributes. +// +//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[repr(transparent)]"]' #[repr(transparent)] pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ()); -//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]' +// Only 1-ZST fields here but none of them are public. +// The attribute isn't included. +// +//@ has "$.index[?(@.name=='AllZstNotPublic')]" +//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '[]' #[repr(transparent)] pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ()); diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs index 08fb80540fa99..ea669e6a0b30f 100644 --- a/tests/rustdoc-json/enums/discriminant/struct.rs +++ b/tests/rustdoc-json/enums/discriminant/struct.rs @@ -1,5 +1,5 @@ #[repr(i32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]' pub enum Foo { //@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs index c74e9a2c58dd4..1b8e791eb2302 100644 --- a/tests/rustdoc-json/enums/discriminant/tuple.rs +++ b/tests/rustdoc-json/enums/discriminant/tuple.rs @@ -1,5 +1,5 @@ #[repr(u32)] -//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]' +//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]' pub enum Foo { //@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null //@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0