Skip to content

Commit bafdbca

Browse files
committed
rustdoc: Use own logic to print #[repr(..)] attributes in JSON output.
1 parent d93f678 commit bafdbca

File tree

10 files changed

+82
-43
lines changed

10 files changed

+82
-43
lines changed

src/librustdoc/clean/types.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -768,12 +768,22 @@ impl Item {
768768
.iter()
769769
.filter_map(|attr| {
770770
if is_json {
771-
if matches!(attr, hir::Attribute::Parsed(AttributeKind::Deprecation { .. })) {
772-
// rustdoc-json stores this in `Item::deprecation`, so we
773-
// don't want it it `Item::attrs`.
774-
None
775-
} else {
776-
Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
771+
match attr {
772+
hir::Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
773+
// rustdoc-json stores this in `Item::deprecation`, so we
774+
// don't want it it `Item::attrs`.
775+
None
776+
}
777+
rustc_hir::Attribute::Parsed(rustc_attr_parsing::AttributeKind::Repr(
778+
..,
779+
)) => {
780+
// We have separate pretty-printing logic for `#[repr(..)]` attributes.
781+
// For example, there are circumstances where `#[repr(transparent)]`
782+
// is applied but should not be publicly shown in rustdoc
783+
// because it isn't public API.
784+
None
785+
}
786+
_ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
777787
}
778788
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
779789
Some(
@@ -789,8 +799,7 @@ impl Item {
789799
.collect();
790800

791801
// Add #[repr(...)]
792-
if !is_json
793-
&& let Some(def_id) = self.def_id()
802+
if let Some(def_id) = self.def_id()
794803
&& let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
795804
{
796805
let adt = tcx.adt_def(def_id);

src/rustdoc-json-types/lib.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
3030
/// This integer is incremented with every breaking change to the API,
3131
/// and is returned along with the JSON blob as [`Crate::format_version`].
3232
/// Consuming code should assert that this value matches the format version(s) that it supports.
33-
pub const FORMAT_VERSION: u32 = 42;
33+
pub const FORMAT_VERSION: u32 = 43;
3434

3535
/// The root of the emitted JSON blob.
3636
///
@@ -120,9 +120,23 @@ pub struct Item {
120120
pub docs: Option<String>,
121121
/// 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
122122
pub links: HashMap<String, Id>,
123-
/// Stringified versions of parsed attributes on this item.
124-
/// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`).
125-
/// Equivalent to the hir pretty-printing of attributes.
123+
/// Attributes on this item.
124+
///
125+
/// Does not include `#[deprecated]` attributes: see the [`Self::deprecation`] field instead.
126+
///
127+
/// Some attributes appear in pretty-printed Rust form, regardless of their formatting
128+
/// in the original source code. For example:
129+
/// - `#[non_exhaustive]` and `#[must_use]` are represented as themselves.
130+
/// - `#[no_mangle]` and `#[export_name]` are also represented as themselves.
131+
/// - `#[repr(C)]` and other reprs also appear as themselves,
132+
/// though potentially with a different order: e.g. `repr(i8, C)` may become `repr(C, i8)`.
133+
/// Multiple repr attributes on the same item may be combined into an equivalent single attr.
134+
///
135+
/// Other attributes may appear debug-printed. For example:
136+
/// - `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`.
137+
///
138+
/// As an internal implementation detail subject to change, this debug-printing format
139+
/// is currently equivalent to the HIR pretty-printing of parsed attributes.
126140
pub attrs: Vec<String>,
127141
/// Information about the item’s deprecation, if present.
128142
pub deprecation: Option<Deprecation>,

tests/rustdoc-json/attrs/repr_align.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![no_std]
22

3-
//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[attr = Repr([ReprAlign(Align(4 bytes))])]\n"]'
3+
//@ is "$.index[?(@.name=='Aligned')].attrs" '["#[repr(align(4))]"]'
44
#[repr(align(4))]
55
pub struct Aligned {
66
a: i8,

tests/rustdoc-json/attrs/repr_c.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
#![no_std]
22

3-
//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[attr = Repr([ReprC])]\n"]'
3+
//@ is "$.index[?(@.name=='ReprCStruct')].attrs" '["#[repr(C)]"]'
44
#[repr(C)]
55
pub struct ReprCStruct(pub i64);
66

7-
//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[attr = Repr([ReprC])]\n"]'
7+
//@ is "$.index[?(@.name=='ReprCEnum')].attrs" '["#[repr(C)]"]'
88
#[repr(C)]
99
pub enum ReprCEnum {
1010
First,
1111
}
1212

13-
//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[attr = Repr([ReprC])]\n"]'
13+
//@ is "$.index[?(@.name=='ReprCUnion')].attrs" '["#[repr(C)]"]'
1414
#[repr(C)]
1515
pub union ReprCUnion {
1616
pub left: i64,

tests/rustdoc-json/attrs/repr_combination.rs

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,78 @@
11
#![no_std]
22

33
// Combinations of `#[repr(..)]` attributes.
4+
// Rustdoc JSON emits normalized output, regardless of the original source.
45

5-
//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I8))])]\n"]'
6+
//@ is "$.index[?(@.name=='ReprCI8')].attrs" '["#[repr(C, i8)]"]'
67
#[repr(C, i8)]
78
pub enum ReprCI8 {
89
First,
910
}
1011

11-
//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[attr = Repr([ReprC, ReprInt(SignedInt(I16))])]\n"]'
12+
//@ is "$.index[?(@.name=='SeparateReprCI16')].attrs" '["#[repr(C, i16)]"]'
1213
#[repr(C)]
1314
#[repr(i16)]
1415
pub enum SeparateReprCI16 {
1516
First,
1617
}
1718

18-
//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize)), ReprC])]\n"]'
19+
//@ is "$.index[?(@.name=='ReversedReprCUsize')].attrs" '["#[repr(C, usize)]"]'
1920
#[repr(usize, C)]
2021
pub enum ReversedReprCUsize {
2122
First,
2223
}
2324

24-
//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(1 bytes))])]\n"]'
25+
//@ is "$.index[?(@.name=='ReprCPacked')].attrs" '["#[repr(C, packed(1))]"]'
2526
#[repr(C, packed)]
2627
pub struct ReprCPacked {
2728
a: i8,
2829
b: i64,
2930
}
3031

31-
//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[attr = Repr([ReprC, ReprPacked(Align(2 bytes))])]\n"]'
32+
//@ is "$.index[?(@.name=='SeparateReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
3233
#[repr(C)]
3334
#[repr(packed(2))]
3435
pub struct SeparateReprCPacked {
3536
a: i8,
3637
b: i64,
3738
}
3839

39-
//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[attr = Repr([ReprPacked(Align(2 bytes)), ReprC])]\n"]'
40+
//@ is "$.index[?(@.name=='ReversedReprCPacked')].attrs" '["#[repr(C, packed(2))]"]'
4041
#[repr(packed(2), C)]
4142
pub struct ReversedReprCPacked {
4243
a: i8,
4344
b: i64,
4445
}
4546

46-
//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes))])]\n"]'
47+
//@ is "$.index[?(@.name=='ReprCAlign')].attrs" '["#[repr(C, align(16))]"]'
4748
#[repr(C, align(16))]
4849
pub struct ReprCAlign {
4950
a: i8,
5051
b: i64,
5152
}
5253

53-
//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(2 bytes))])]\n"]'
54+
//@ is "$.index[?(@.name=='SeparateReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
5455
#[repr(C)]
5556
#[repr(align(2))]
5657
pub struct SeparateReprCAlign {
5758
a: i8,
5859
b: i64,
5960
}
6061

61-
//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[attr = Repr([ReprAlign(Align(2 bytes)), ReprC])]\n"]'
62+
//@ is "$.index[?(@.name=='ReversedReprCAlign')].attrs" '["#[repr(C, align(2))]"]'
6263
#[repr(align(2), C)]
6364
pub struct ReversedReprCAlign {
6465
a: i8,
6566
b: i64,
6667
}
6768

68-
//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprC, ReprAlign(Align(16 bytes)), ReprInt(SignedInt(Isize))])]\n"]'
69+
//@ is "$.index[?(@.name=='AlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
6970
#[repr(C, align(16), isize)]
7071
pub enum AlignedExplicitRepr {
7172
First,
7273
}
7374

74-
//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[attr = Repr([ReprInt(SignedInt(Isize)), ReprC, ReprAlign(Align(16 bytes))])]\n"]'
75+
//@ is "$.index[?(@.name=='ReorderedAlignedExplicitRepr')].attrs" '["#[repr(C, align(16), isize)]"]'
7576
#[repr(isize, C, align(16))]
7677
pub enum ReorderedAlignedExplicitRepr {
7778
First,

tests/rustdoc-json/attrs/repr_int_enum.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
#![no_std]
22

3-
//@ is "$.index[?(@.name=='I8')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I8))])]\n"]'
3+
//@ is "$.index[?(@.name=='I8')].attrs" '["#[repr(i8)]"]'
44
#[repr(i8)]
55
pub enum I8 {
66
First,
77
}
88

9-
//@ is "$.index[?(@.name=='I32')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
9+
//@ is "$.index[?(@.name=='I32')].attrs" '["#[repr(i32)]"]'
1010
#[repr(i32)]
1111
pub enum I32 {
1212
First,
1313
}
1414

15-
//@ is "$.index[?(@.name=='Usize')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(Usize))])]\n"]'
15+
//@ is "$.index[?(@.name=='Usize')].attrs" '["#[repr(usize)]"]'
1616
#[repr(usize)]
1717
pub enum Usize {
1818
First,

tests/rustdoc-json/attrs/repr_packed.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
#![no_std]
22

33
// Note the normalization:
4-
// `#[repr(packed)]` in has the implict "1" in rustdoc JSON.
5-
6-
//@ is "$.index[?(@.name=='Packed')].attrs" '["#[attr = Repr([ReprPacked(Align(1 bytes))])]\n"]'
4+
// `#[repr(packed)]` in source becomes `#[repr(packed(1))]` in rustdoc JSON.
5+
//
6+
//@ is "$.index[?(@.name=='Packed')].attrs" '["#[repr(packed(1))]"]'
77
#[repr(packed)]
88
pub struct Packed {
99
a: i8,
1010
b: i64,
1111
}
1212

13-
//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[attr = Repr([ReprPacked(Align(4 bytes))])]\n"]'
13+
//@ is "$.index[?(@.name=='PackedAligned')].attrs" '["#[repr(packed(4))]"]'
1414
#[repr(packed(4))]
1515
pub struct PackedAligned {
1616
a: i8,
+22-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
11
#![no_std]
22

3-
// Rustdoc JSON currently includes `#[repr(transparent)]`
4-
// even if the transparency is not part of the public API
3+
// Rustdoc JSON *only* includes `#[repr(transparent)]`
4+
// if the transparency is public API:
5+
// - if a non-1-ZST field exists, it has to be public
6+
// - otherwise, all fields are 1-ZST and at least one of them is public
57
//
6-
// https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
8+
// More info: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
79

8-
//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
10+
// Here, the non-1-ZST field is public.
11+
// We expect `#[repr(transparent)]` in the attributes.
12+
//
13+
//@ is "$.index[?(@.name=='Transparent')].attrs" '["#[repr(transparent)]"]'
914
#[repr(transparent)]
1015
pub struct Transparent(pub i64);
1116

12-
//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
17+
// Here the non-1-ZST field isn't public, so the attribute isn't included.
18+
//
19+
//@ has "$.index[?(@.name=='TransparentNonPub')]"
20+
//@ is "$.index[?(@.name=='TransparentNonPub')].attrs" '[]'
1321
#[repr(transparent)]
1422
pub struct TransparentNonPub(i64);
1523

16-
//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
24+
// Only 1-ZST fields here, and one of them is public.
25+
// We expect `#[repr(transparent)]` in the attributes.
26+
//
27+
//@ is "$.index[?(@.name=='AllZst')].attrs" '["#[repr(transparent)]"]'
1728
#[repr(transparent)]
1829
pub struct AllZst<'a>(pub core::marker::PhantomData<&'a ()>, ());
1930

20-
//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '["#[attr = Repr([ReprTransparent])]\n"]'
31+
// Only 1-ZST fields here but none of them are public.
32+
// The attribute isn't included.
33+
//
34+
//@ has "$.index[?(@.name=='AllZstNotPublic')]"
35+
//@ is "$.index[?(@.name=='AllZstNotPublic')].attrs" '[]'
2136
#[repr(transparent)]
2237
pub struct AllZstNotPublic<'a>(core::marker::PhantomData<&'a ()>, ());

tests/rustdoc-json/enums/discriminant/struct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[repr(i32)]
2-
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
2+
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
33
pub enum Foo {
44
//@ is "$.index[?(@.name=='Struct')].inner.variant.discriminant" null
55
//@ count "$.index[?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0

tests/rustdoc-json/enums/discriminant/tuple.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#[repr(u32)]
2-
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]'
2+
//@ is "$.index[?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
33
pub enum Foo {
44
//@ is "$.index[?(@.name=='Tuple')].inner.variant.discriminant" null
55
//@ count "$.index[?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0

0 commit comments

Comments
 (0)