Skip to content

Commit 549b3a1

Browse files
authored
Rollup merge of #110983 - GuillaumeGomez:foreign-repr, r=notriddle
rustdoc: Get `repr` information through `AdtDef` for foreign items As suggested by `@notriddle,` this approach works too. The only downside is that the display of the original attribute isn't kept, but I think it's an acceptable downside. r? `@notriddle`
2 parents 4b79276 + b778688 commit 549b3a1

File tree

8 files changed

+136
-54
lines changed

8 files changed

+136
-54
lines changed

compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
344344
),
345345
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
346346
ungated!(no_link, Normal, template!(Word), WarnFollowing),
347-
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
347+
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
348348
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
349349
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
350350
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),

src/librustdoc/clean/types.rs

+73
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use arrayvec::ArrayVec;
1111
use thin_vec::ThinVec;
1212

1313
use rustc_ast as ast;
14+
use rustc_ast_pretty::pprust;
1415
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
1516
use rustc_const_eval::const_eval::is_unstable_const_fn;
1617
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -711,6 +712,78 @@ impl Item {
711712
};
712713
Some(tcx.visibility(def_id))
713714
}
715+
716+
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
717+
const ALLOWED_ATTRIBUTES: &[Symbol] =
718+
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
719+
720+
use rustc_abi::IntegerType;
721+
use rustc_middle::ty::ReprFlags;
722+
723+
let mut attrs: Vec<String> = self
724+
.attrs
725+
.other_attrs
726+
.iter()
727+
.filter_map(|attr| {
728+
if keep_as_is {
729+
Some(pprust::attribute_to_string(attr))
730+
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
731+
Some(
732+
pprust::attribute_to_string(attr)
733+
.replace("\\\n", "")
734+
.replace('\n', "")
735+
.replace(" ", " "),
736+
)
737+
} else {
738+
None
739+
}
740+
})
741+
.collect();
742+
if let Some(def_id) = self.item_id.as_def_id() &&
743+
!def_id.is_local() &&
744+
// This check is needed because `adt_def` will panic if not a compatible type otherwise...
745+
matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
746+
{
747+
let repr = tcx.adt_def(def_id).repr();
748+
let mut out = Vec::new();
749+
if repr.flags.contains(ReprFlags::IS_C) {
750+
out.push("C");
751+
}
752+
if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
753+
out.push("transparent");
754+
}
755+
if repr.flags.contains(ReprFlags::IS_SIMD) {
756+
out.push("simd");
757+
}
758+
let pack_s;
759+
if let Some(pack) = repr.pack {
760+
pack_s = format!("packed({})", pack.bytes());
761+
out.push(&pack_s);
762+
}
763+
let align_s;
764+
if let Some(align) = repr.align {
765+
align_s = format!("align({})", align.bytes());
766+
out.push(&align_s);
767+
}
768+
let int_s;
769+
if let Some(int) = repr.int {
770+
int_s = match int {
771+
IntegerType::Pointer(is_signed) => {
772+
format!("{}size", if is_signed { 'i' } else { 'u' })
773+
}
774+
IntegerType::Fixed(size, is_signed) => {
775+
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
776+
}
777+
};
778+
out.push(&int_s);
779+
}
780+
if out.is_empty() {
781+
return Vec::new();
782+
}
783+
attrs.push(format!("#[repr({})]", out.join(", ")));
784+
}
785+
attrs
786+
}
714787
}
715788

716789
#[derive(Clone, Debug)]

src/librustdoc/html/render/mod.rs

+8-30
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ use std::str;
4848
use std::string::ToString;
4949

5050
use askama::Template;
51-
use rustc_ast_pretty::pprust;
5251
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
5352
use rustc_data_structures::captures::Captures;
5453
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -849,10 +848,10 @@ fn assoc_method(
849848
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
850849
header_len += 4;
851850
let indent_str = " ";
852-
write!(w, "{}", render_attributes_in_pre(meth, indent_str));
851+
write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
853852
(4, indent_str, Ending::NoNewline)
854853
} else {
855-
render_attributes_in_code(w, meth);
854+
render_attributes_in_code(w, meth, tcx);
856855
(0, "", Ending::Newline)
857856
};
858857
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
@@ -1021,36 +1020,15 @@ fn render_assoc_item(
10211020
}
10221021
}
10231022

1024-
const ALLOWED_ATTRIBUTES: &[Symbol] =
1025-
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
1026-
1027-
fn attributes(it: &clean::Item) -> Vec<String> {
1028-
it.attrs
1029-
.other_attrs
1030-
.iter()
1031-
.filter_map(|attr| {
1032-
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
1033-
Some(
1034-
pprust::attribute_to_string(attr)
1035-
.replace("\\\n", "")
1036-
.replace('\n', "")
1037-
.replace(" ", " "),
1038-
)
1039-
} else {
1040-
None
1041-
}
1042-
})
1043-
.collect()
1044-
}
1045-
10461023
// When an attribute is rendered inside a `<pre>` tag, it is formatted using
10471024
// a whitespace prefix and newline.
1048-
fn render_attributes_in_pre<'a>(
1025+
fn render_attributes_in_pre<'a, 'b: 'a>(
10491026
it: &'a clean::Item,
10501027
prefix: &'a str,
1051-
) -> impl fmt::Display + Captures<'a> {
1028+
tcx: TyCtxt<'b>,
1029+
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
10521030
crate::html::format::display_fn(move |f| {
1053-
for a in attributes(it) {
1031+
for a in it.attributes(tcx, false) {
10541032
writeln!(f, "{}{}", prefix, a)?;
10551033
}
10561034
Ok(())
@@ -1059,8 +1037,8 @@ fn render_attributes_in_pre<'a>(
10591037

10601038
// When an attribute is rendered inside a <code> tag, it is formatted using
10611039
// a div to produce a newline after it.
1062-
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
1063-
for a in attributes(it) {
1040+
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
1041+
for a in it.attributes(tcx, false) {
10641042
write!(w, "<div class=\"code-attribute\">{}</div>", a);
10651043
}
10661044
}

src/librustdoc/html/render/print_item.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
548548
w,
549549
"{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
550550
{name}{generics}{decl}{notable_traits}{where_clause}",
551-
attrs = render_attributes_in_pre(it, ""),
551+
attrs = render_attributes_in_pre(it, "", tcx),
552552
vis = visibility,
553553
constness = constness,
554554
asyncness = asyncness,
@@ -589,7 +589,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
589589
it.name.unwrap(),
590590
t.generics.print(cx),
591591
bounds,
592-
attrs = render_attributes_in_pre(it, ""),
592+
attrs = render_attributes_in_pre(it, "", tcx),
593593
);
594594

595595
if !t.generics.where_predicates.is_empty() {
@@ -1063,7 +1063,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
10631063
t.generics.print(cx),
10641064
print_where_clause(&t.generics, cx, 0, Ending::Newline),
10651065
bounds(&t.bounds, true, cx),
1066-
attrs = render_attributes_in_pre(it, ""),
1066+
attrs = render_attributes_in_pre(it, "", cx.tcx()),
10671067
);
10681068
});
10691069

@@ -1085,7 +1085,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
10851085
t.generics.print(cx),
10861086
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
10871087
bounds = bounds(&t.bounds, false, cx),
1088-
attrs = render_attributes_in_pre(it, ""),
1088+
attrs = render_attributes_in_pre(it, "", cx.tcx()),
10891089
);
10901090
});
10911091

@@ -1109,7 +1109,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
11091109
t.generics.print(cx),
11101110
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
11111111
type_ = t.type_.print(cx),
1112-
attrs = render_attributes_in_pre(it, ""),
1112+
attrs = render_attributes_in_pre(it, "", cx.tcx()),
11131113
);
11141114
});
11151115
}
@@ -1168,7 +1168,8 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
11681168
&'b self,
11691169
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
11701170
display_fn(move |f| {
1171-
let v = render_attributes_in_pre(self.it, "");
1171+
let tcx = self.cx.borrow().tcx();
1172+
let v = render_attributes_in_pre(self.it, "", tcx);
11721173
write!(f, "{v}")
11731174
})
11741175
}
@@ -1244,13 +1245,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
12441245
let tcx = cx.tcx();
12451246
let count_variants = e.variants().count();
12461247
wrap_item(w, |mut w| {
1248+
render_attributes_in_code(w, it, tcx);
12471249
write!(
12481250
w,
1249-
"{attrs}{}enum {}{}",
1251+
"{}enum {}{}",
12501252
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
12511253
it.name.unwrap(),
12521254
e.generics.print(cx),
1253-
attrs = render_attributes_in_pre(it, ""),
12541255
);
12551256
if !print_where_clause_and_check(w, &e.generics, cx) {
12561257
// If there wasn't a `where` clause, we add a whitespace.
@@ -1445,7 +1446,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
14451446
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
14461447
wrap_item(w, |w| {
14471448
let tcx = cx.tcx();
1448-
render_attributes_in_code(w, it);
1449+
render_attributes_in_code(w, it, tcx);
14491450

14501451
write!(
14511452
w,
@@ -1492,7 +1493,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
14921493

14931494
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
14941495
wrap_item(w, |w| {
1495-
render_attributes_in_code(w, it);
1496+
render_attributes_in_code(w, it, cx.tcx());
14961497
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
14971498
});
14981499

@@ -1542,7 +1543,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
15421543

15431544
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
15441545
wrap_item(w, |w| {
1545-
render_attributes_in_code(w, it);
1546+
render_attributes_in_code(w, it, cx.tcx());
15461547
write!(
15471548
w,
15481549
"{vis}static {mutability}{name}: {typ}",
@@ -1558,7 +1559,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
15581559
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
15591560
wrap_item(w, |w| {
15601561
w.write_str("extern {\n");
1561-
render_attributes_in_code(w, it);
1562+
render_attributes_in_code(w, it, cx.tcx());
15621563
write!(
15631564
w,
15641565
" {}type {};\n}}",

src/librustdoc/json/conversions.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,7 @@ impl JsonRenderer<'_> {
4141
})
4242
.collect();
4343
let docs = item.attrs.collapsed_doc_value();
44-
let attrs = item
45-
.attrs
46-
.other_attrs
47-
.iter()
48-
.map(rustc_ast_pretty::pprust::attribute_to_string)
49-
.collect();
44+
let attrs = item.attributes(self.tcx, true);
5045
let span = item.span(self.tcx);
5146
let visibility = item.visibility(self.tcx);
5247
let clean::Item { name, item_id, .. } = item;

src/librustdoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern crate tracing;
3434
// Dependencies listed in Cargo.toml do not need `extern crate`.
3535

3636
extern crate pulldown_cmark;
37+
extern crate rustc_abi;
3738
extern crate rustc_ast;
3839
extern crate rustc_ast_pretty;
3940
extern crate rustc_attr;
+20-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1-
#[repr(C)]
2-
pub struct Foo {
1+
#![feature(repr_simd)]
2+
3+
#[repr(C, align(8))]
4+
pub struct ReprC {
35
field: u8,
46
}
7+
#[repr(simd, packed(2))]
8+
pub struct ReprSimd {
9+
field: u8,
10+
}
11+
#[repr(transparent)]
12+
pub struct ReprTransparent {
13+
field: u8,
14+
}
15+
#[repr(isize)]
16+
pub enum ReprIsize {
17+
Bla,
18+
}
19+
#[repr(u8)]
20+
pub enum ReprU8 {
21+
Bla,
22+
}

tests/rustdoc/inline_cross/repr.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,23 @@
77

88
extern crate repr;
99

10-
// @has 'foo/struct.Foo.html'
11-
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
10+
// @has 'foo/struct.ReprC.html'
11+
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
1212
#[doc(inline)]
13-
pub use repr::Foo;
13+
pub use repr::ReprC;
14+
// @has 'foo/struct.ReprSimd.html'
15+
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
16+
#[doc(inline)]
17+
pub use repr::ReprSimd;
18+
// @has 'foo/struct.ReprTransparent.html'
19+
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
20+
#[doc(inline)]
21+
pub use repr::ReprTransparent;
22+
// @has 'foo/enum.ReprIsize.html'
23+
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
24+
#[doc(inline)]
25+
pub use repr::ReprIsize;
26+
// @has 'foo/enum.ReprU8.html'
27+
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
28+
#[doc(inline)]
29+
pub use repr::ReprU8;

0 commit comments

Comments
 (0)