1
Fork 0

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`
This commit is contained in:
Matthias Krüger 2023-04-30 01:14:59 +02:00 committed by GitHub
commit 549b3a13a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 136 additions and 54 deletions

View file

@ -344,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_link, Normal, template!(Word), WarnFollowing), ungated!(no_link, Normal, template!(Word), WarnFollowing),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),

View file

@ -11,6 +11,7 @@ use arrayvec::ArrayVec;
use thin_vec::ThinVec; use thin_vec::ThinVec;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_const_eval::const_eval::is_unstable_const_fn;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -711,6 +712,78 @@ impl Item {
}; };
Some(tcx.visibility(def_id)) Some(tcx.visibility(def_id))
} }
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> {
const ALLOWED_ATTRIBUTES: &[Symbol] =
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
use rustc_abi::IntegerType;
use rustc_middle::ty::ReprFlags;
let mut attrs: Vec<String> = self
.attrs
.other_attrs
.iter()
.filter_map(|attr| {
if keep_as_is {
Some(pprust::attribute_to_string(attr))
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
Some(
pprust::attribute_to_string(attr)
.replace("\\\n", "")
.replace('\n', "")
.replace(" ", " "),
)
} else {
None
}
})
.collect();
if let Some(def_id) = self.item_id.as_def_id() &&
!def_id.is_local() &&
// This check is needed because `adt_def` will panic if not a compatible type otherwise...
matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union)
{
let repr = tcx.adt_def(def_id).repr();
let mut out = Vec::new();
if repr.flags.contains(ReprFlags::IS_C) {
out.push("C");
}
if repr.flags.contains(ReprFlags::IS_TRANSPARENT) {
out.push("transparent");
}
if repr.flags.contains(ReprFlags::IS_SIMD) {
out.push("simd");
}
let pack_s;
if let Some(pack) = repr.pack {
pack_s = format!("packed({})", pack.bytes());
out.push(&pack_s);
}
let align_s;
if let Some(align) = repr.align {
align_s = format!("align({})", align.bytes());
out.push(&align_s);
}
let int_s;
if let Some(int) = repr.int {
int_s = match int {
IntegerType::Pointer(is_signed) => {
format!("{}size", if is_signed { 'i' } else { 'u' })
}
IntegerType::Fixed(size, is_signed) => {
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
}
};
out.push(&int_s);
}
if out.is_empty() {
return Vec::new();
}
attrs.push(format!("#[repr({})]", out.join(", ")));
}
attrs
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View file

@ -48,7 +48,6 @@ use std::str;
use std::string::ToString; use std::string::ToString;
use askama::Template; use askama::Template;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -849,10 +848,10 @@ fn assoc_method(
let (indent, indent_str, end_newline) = if parent == ItemType::Trait { let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
header_len += 4; header_len += 4;
let indent_str = " "; let indent_str = " ";
write!(w, "{}", render_attributes_in_pre(meth, indent_str)); write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx));
(4, indent_str, Ending::NoNewline) (4, indent_str, Ending::NoNewline)
} else { } else {
render_attributes_in_code(w, meth); render_attributes_in_code(w, meth, tcx);
(0, "", Ending::Newline) (0, "", Ending::Newline)
}; };
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len()); w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
@ -1021,36 +1020,15 @@ fn render_assoc_item(
} }
} }
const ALLOWED_ATTRIBUTES: &[Symbol] =
&[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
fn attributes(it: &clean::Item) -> Vec<String> {
it.attrs
.other_attrs
.iter()
.filter_map(|attr| {
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
Some(
pprust::attribute_to_string(attr)
.replace("\\\n", "")
.replace('\n', "")
.replace(" ", " "),
)
} else {
None
}
})
.collect()
}
// When an attribute is rendered inside a `<pre>` tag, it is formatted using // When an attribute is rendered inside a `<pre>` tag, it is formatted using
// a whitespace prefix and newline. // a whitespace prefix and newline.
fn render_attributes_in_pre<'a>( fn render_attributes_in_pre<'a, 'b: 'a>(
it: &'a clean::Item, it: &'a clean::Item,
prefix: &'a str, prefix: &'a str,
) -> impl fmt::Display + Captures<'a> { tcx: TyCtxt<'b>,
) -> impl fmt::Display + Captures<'a> + Captures<'b> {
crate::html::format::display_fn(move |f| { crate::html::format::display_fn(move |f| {
for a in attributes(it) { for a in it.attributes(tcx, false) {
writeln!(f, "{}{}", prefix, a)?; writeln!(f, "{}{}", prefix, a)?;
} }
Ok(()) Ok(())
@ -1059,8 +1037,8 @@ fn render_attributes_in_pre<'a>(
// When an attribute is rendered inside a <code> tag, it is formatted using // When an attribute is rendered inside a <code> tag, it is formatted using
// a div to produce a newline after it. // a div to produce a newline after it.
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) { fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
for a in attributes(it) { for a in it.attributes(tcx, false) {
write!(w, "<div class=\"code-attribute\">{}</div>", a); write!(w, "<div class=\"code-attribute\">{}</div>", a);
} }
} }

View file

@ -548,7 +548,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
w, w,
"{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{notable_traits}{where_clause}", {name}{generics}{decl}{notable_traits}{where_clause}",
attrs = render_attributes_in_pre(it, ""), attrs = render_attributes_in_pre(it, "", tcx),
vis = visibility, vis = visibility,
constness = constness, constness = constness,
asyncness = asyncness, asyncness = asyncness,
@ -589,7 +589,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
it.name.unwrap(), it.name.unwrap(),
t.generics.print(cx), t.generics.print(cx),
bounds, bounds,
attrs = render_attributes_in_pre(it, ""), attrs = render_attributes_in_pre(it, "", tcx),
); );
if !t.generics.where_predicates.is_empty() { 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: &
t.generics.print(cx), t.generics.print(cx),
print_where_clause(&t.generics, cx, 0, Ending::Newline), print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds(&t.bounds, true, cx), bounds(&t.bounds, true, cx),
attrs = render_attributes_in_pre(it, ""), attrs = render_attributes_in_pre(it, "", cx.tcx()),
); );
}); });
@ -1085,7 +1085,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
t.generics.print(cx), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds = bounds(&t.bounds, false, cx), bounds = bounds(&t.bounds, false, cx),
attrs = render_attributes_in_pre(it, ""), attrs = render_attributes_in_pre(it, "", cx.tcx()),
); );
}); });
@ -1109,7 +1109,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
t.generics.print(cx), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
type_ = t.type_.print(cx), type_ = t.type_.print(cx),
attrs = render_attributes_in_pre(it, ""), attrs = render_attributes_in_pre(it, "", cx.tcx()),
); );
}); });
} }
@ -1168,7 +1168,8 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
&'b self, &'b self,
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
display_fn(move |f| { display_fn(move |f| {
let v = render_attributes_in_pre(self.it, ""); let tcx = self.cx.borrow().tcx();
let v = render_attributes_in_pre(self.it, "", tcx);
write!(f, "{v}") write!(f, "{v}")
}) })
} }
@ -1244,13 +1245,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let tcx = cx.tcx(); let tcx = cx.tcx();
let count_variants = e.variants().count(); let count_variants = e.variants().count();
wrap_item(w, |mut w| { wrap_item(w, |mut w| {
render_attributes_in_code(w, it, tcx);
write!( write!(
w, w,
"{attrs}{}enum {}{}", "{}enum {}{}",
visibility_print_with_space(it.visibility(tcx), it.item_id, cx), visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
it.name.unwrap(), it.name.unwrap(),
e.generics.print(cx), e.generics.print(cx),
attrs = render_attributes_in_pre(it, ""),
); );
if !print_where_clause_and_check(w, &e.generics, cx) { if !print_where_clause_and_check(w, &e.generics, cx) {
// If there wasn't a `where` clause, we add a whitespace. // 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) {
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
wrap_item(w, |w| { wrap_item(w, |w| {
let tcx = cx.tcx(); let tcx = cx.tcx();
render_attributes_in_code(w, it); render_attributes_in_code(w, it, tcx);
write!( write!(
w, w,
@ -1492,7 +1493,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
wrap_item(w, |w| { wrap_item(w, |w| {
render_attributes_in_code(w, it); render_attributes_in_code(w, it, cx.tcx());
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
}); });
@ -1542,7 +1543,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
wrap_item(w, |w| { wrap_item(w, |w| {
render_attributes_in_code(w, it); render_attributes_in_code(w, it, cx.tcx());
write!( write!(
w, w,
"{vis}static {mutability}{name}: {typ}", "{vis}static {mutability}{name}: {typ}",
@ -1558,7 +1559,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
wrap_item(w, |w| { wrap_item(w, |w| {
w.write_str("extern {\n"); w.write_str("extern {\n");
render_attributes_in_code(w, it); render_attributes_in_code(w, it, cx.tcx());
write!( write!(
w, w,
" {}type {};\n}}", " {}type {};\n}}",

View file

@ -41,12 +41,7 @@ impl JsonRenderer<'_> {
}) })
.collect(); .collect();
let docs = item.attrs.collapsed_doc_value(); let docs = item.attrs.collapsed_doc_value();
let attrs = item let attrs = item.attributes(self.tcx, true);
.attrs
.other_attrs
.iter()
.map(rustc_ast_pretty::pprust::attribute_to_string)
.collect();
let span = item.span(self.tcx); let span = item.span(self.tcx);
let visibility = item.visibility(self.tcx); let visibility = item.visibility(self.tcx);
let clean::Item { name, item_id, .. } = item; let clean::Item { name, item_id, .. } = item;

View file

@ -34,6 +34,7 @@ extern crate tracing;
// Dependencies listed in Cargo.toml do not need `extern crate`. // Dependencies listed in Cargo.toml do not need `extern crate`.
extern crate pulldown_cmark; extern crate pulldown_cmark;
extern crate rustc_abi;
extern crate rustc_ast; extern crate rustc_ast;
extern crate rustc_ast_pretty; extern crate rustc_ast_pretty;
extern crate rustc_attr; extern crate rustc_attr;

View file

@ -1,4 +1,22 @@
#[repr(C)] #![feature(repr_simd)]
pub struct Foo {
#[repr(C, align(8))]
pub struct ReprC {
field: u8, field: u8,
} }
#[repr(simd, packed(2))]
pub struct ReprSimd {
field: u8,
}
#[repr(transparent)]
pub struct ReprTransparent {
field: u8,
}
#[repr(isize)]
pub enum ReprIsize {
Bla,
}
#[repr(u8)]
pub enum ReprU8 {
Bla,
}

View file

@ -7,7 +7,23 @@
extern crate repr; extern crate repr;
// @has 'foo/struct.Foo.html' // @has 'foo/struct.ReprC.html'
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
#[doc(inline)] #[doc(inline)]
pub use repr::Foo; pub use repr::ReprC;
// @has 'foo/struct.ReprSimd.html'
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
#[doc(inline)]
pub use repr::ReprSimd;
// @has 'foo/struct.ReprTransparent.html'
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
#[doc(inline)]
pub use repr::ReprTransparent;
// @has 'foo/enum.ReprIsize.html'
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
#[doc(inline)]
pub use repr::ReprIsize;
// @has 'foo/enum.ReprU8.html'
// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
#[doc(inline)]
pub use repr::ReprU8;