about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-04-30 01:14:59 +0200
committerGitHub <noreply@github.com>2023-04-30 01:14:59 +0200
commit549b3a13a15b5727846ef9ad24ab70ce970d794c (patch)
treecd5af8a090ba17e29b4ec25d6a7d1b35eaafec28
parent4b79276e60398cdce8766c6fbfa694bf7325a95c (diff)
parentb778688f913bf6d3735b0b603b41c6989f513399 (diff)
downloadrust-549b3a13a15b5727846ef9ad24ab70ce970d794c.tar.gz
rust-549b3a13a15b5727846ef9ad24ab70ce970d794c.zip
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`
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--src/librustdoc/clean/types.rs73
-rw-r--r--src/librustdoc/html/render/mod.rs38
-rw-r--r--src/librustdoc/html/render/print_item.rs25
-rw-r--r--src/librustdoc/json/conversions.rs7
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/repr.rs22
-rw-r--r--tests/rustdoc/inline_cross/repr.rs22
8 files changed, 136 insertions, 54 deletions
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 103e0f34407..c77292fdd16 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -344,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     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!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 74f330b7621..7371b44465b 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -11,6 +11,7 @@ use arrayvec::ArrayVec;
 use thin_vec::ThinVec;
 
 use rustc_ast as ast;
+use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
 use rustc_const_eval::const_eval::is_unstable_const_fn;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -711,6 +712,78 @@ impl Item {
         };
         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)]
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index d90d0aecb93..73bf27c9d34 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -48,7 +48,6 @@ use std::str;
 use std::string::ToString;
 
 use askama::Template;
-use rustc_ast_pretty::pprust;
 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -849,10 +848,10 @@ fn assoc_method(
     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
         header_len += 4;
         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)
     } else {
-        render_attributes_in_code(w, meth);
+        render_attributes_in_code(w, meth, tcx);
         (0, "", Ending::Newline)
     };
     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
 // a whitespace prefix and newline.
-fn render_attributes_in_pre<'a>(
+fn render_attributes_in_pre<'a, 'b: 'a>(
     it: &'a clean::Item,
     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| {
-        for a in attributes(it) {
+        for a in it.attributes(tcx, false) {
             writeln!(f, "{}{}", prefix, a)?;
         }
         Ok(())
@@ -1059,8 +1037,8 @@ fn render_attributes_in_pre<'a>(
 
 // When an attribute is rendered inside a <code> tag, it is formatted using
 // a div to produce a newline after it.
-fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
-    for a in attributes(it) {
+fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
+    for a in it.attributes(tcx, false) {
         write!(w, "<div class=\"code-attribute\">{}</div>", a);
     }
 }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 3e71d41ec96..4cc81e860f0 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -548,7 +548,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
             w,
             "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
-            attrs = render_attributes_in_pre(it, ""),
+            attrs = render_attributes_in_pre(it, "", tcx),
             vis = visibility,
             constness = constness,
             asyncness = asyncness,
@@ -589,7 +589,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             it.name.unwrap(),
             t.generics.print(cx),
             bounds,
-            attrs = render_attributes_in_pre(it, ""),
+            attrs = render_attributes_in_pre(it, "", tcx),
         );
 
         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),
             print_where_clause(&t.generics, cx, 0, Ending::Newline),
             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),
             where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
             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),
                 where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
                 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,
         ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
             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}")
             })
         }
@@ -1244,13 +1245,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
     let tcx = cx.tcx();
     let count_variants = e.variants().count();
     wrap_item(w, |mut w| {
+        render_attributes_in_code(w, it, tcx);
         write!(
             w,
-            "{attrs}{}enum {}{}",
+            "{}enum {}{}",
             visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
             it.name.unwrap(),
             e.generics.print(cx),
-            attrs = render_attributes_in_pre(it, ""),
         );
         if !print_where_clause_and_check(w, &e.generics, cx) {
             // 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) {
     wrap_item(w, |w| {
         let tcx = cx.tcx();
-        render_attributes_in_code(w, it);
+        render_attributes_in_code(w, it, tcx);
 
         write!(
             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) {
     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);
     });
 
@@ -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) {
     wrap_item(w, |w| {
-        render_attributes_in_code(w, it);
+        render_attributes_in_code(w, it, cx.tcx());
         write!(
             w,
             "{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) {
     wrap_item(w, |w| {
         w.write_str("extern {\n");
-        render_attributes_in_code(w, it);
+        render_attributes_in_code(w, it, cx.tcx());
         write!(
             w,
             "    {}type {};\n}}",
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index edd046ab772..62aab46fa7e 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -41,12 +41,7 @@ impl JsonRenderer<'_> {
             })
             .collect();
         let docs = item.attrs.collapsed_doc_value();
-        let attrs = item
-            .attrs
-            .other_attrs
-            .iter()
-            .map(rustc_ast_pretty::pprust::attribute_to_string)
-            .collect();
+        let attrs = item.attributes(self.tcx, true);
         let span = item.span(self.tcx);
         let visibility = item.visibility(self.tcx);
         let clean::Item { name, item_id, .. } = item;
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 60754130d99..66080f64b9c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -34,6 +34,7 @@ extern crate tracing;
 // Dependencies listed in Cargo.toml do not need `extern crate`.
 
 extern crate pulldown_cmark;
+extern crate rustc_abi;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs
index 64a98f18146..4a6648a6439 100644
--- a/tests/rustdoc/inline_cross/auxiliary/repr.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/repr.rs
@@ -1,4 +1,22 @@
-#[repr(C)]
-pub struct Foo {
+#![feature(repr_simd)]
+
+#[repr(C, align(8))]
+pub struct ReprC {
     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,
+}
diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs
index 7e1f2799af1..9e107cee9e9 100644
--- a/tests/rustdoc/inline_cross/repr.rs
+++ b/tests/rustdoc/inline_cross/repr.rs
@@ -7,7 +7,23 @@
 
 extern crate repr;
 
-// @has 'foo/struct.Foo.html'
-// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+// @has 'foo/struct.ReprC.html'
+// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
 #[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;