about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-09-25 20:35:49 +0000
committerbors <bors@rust-lang.org>2025-09-25 20:35:49 +0000
commit7ac0330c6d684d86d6f86fabe601a3defdc3b234 (patch)
tree5c1a901b7316ab94dc6ad125c5524a23f86bd101
parenteabf390b4ceeb34db9f37e97f435134abbcdea92 (diff)
parentc6d0059fb887c172a9325adae78548c975653572 (diff)
downloadrust-7ac0330c6d684d86d6f86fabe601a3defdc3b234.tar.gz
rust-7ac0330c6d684d86d6f86fabe601a3defdc3b234.zip
Auto merge of #147037 - matthiaskrgr:rollup-xtgqzuu, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#116882 (rustdoc: hide `#[repr]` if it isn't part of the public ABI)
 - rust-lang/rust#135771 ([rustdoc] Add support for associated items in "jump to def" feature)
 - rust-lang/rust#141032 (avoid violating `slice::from_raw_parts` safety contract in `Vec::extract_if`)
 - rust-lang/rust#142401 (Add proper name mangling for pattern types)
 - rust-lang/rust#146293 (feat: non-panicking `Vec::try_remove`)
 - rust-lang/rust#146859 (BTreeMap: Don't leak allocators when initializing nodes)
 - rust-lang/rust#146924 (Add doc for `NonZero*` const creation)
 - rust-lang/rust#146933 (Make `render_example_with_highlighting` return an `impl fmt::Display`)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs14
-rw-r--r--library/alloc/src/collections/btree/map.rs3
-rw-r--r--library/alloc/src/collections/btree/node.rs12
-rw-r--r--library/alloc/src/vec/extract_if.rs64
-rw-r--r--library/alloc/src/vec/mod.rs32
-rw-r--r--library/alloctests/tests/lib.rs1
-rw-r--r--library/alloctests/tests/vec.rs15
-rw-r--r--library/core/src/num/nonzero.rs12
-rw-r--r--src/doc/rustc/src/symbol-mangling/v0.md28
-rw-r--r--src/doc/rustdoc/src/advanced-features.md20
-rw-r--r--src/librustdoc/clean/types.rs112
-rw-r--r--src/librustdoc/html/highlight.rs250
-rw-r--r--src/librustdoc/html/markdown.rs45
-rw-r--r--src/librustdoc/html/render/mod.rs180
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/html/render/span_map.rs124
-rw-r--r--src/tools/miri/tests/pass/vec.rs10
-rw-r--r--tests/codegen-llvm/pattern_type_symbols.rs4
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs8
-rw-r--r--tests/rustdoc/attribute-rendering.rs8
-rw-r--r--tests/rustdoc/attributes.rs12
-rw-r--r--tests/rustdoc/auxiliary/ext-repr.rs5
-rw-r--r--tests/rustdoc/inline_cross/attributes.rs17
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/attributes.rs9
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/repr.rs42
-rw-r--r--tests/rustdoc/inline_cross/repr.rs40
-rw-r--r--tests/rustdoc/jump-to-def-assoc-items.rs54
-rw-r--r--tests/rustdoc/jump-to-def-ice-assoc-types.rs20
-rw-r--r--tests/rustdoc/jump-to-def-ice.rs24
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs4
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-def-pats.rs10
-rw-r--r--tests/rustdoc/jump-to-def/jump-to-non-local-method.rs7
-rw-r--r--tests/rustdoc/reexport/auxiliary/reexports-attrs.rs14
-rw-r--r--tests/rustdoc/reexport/reexport-attrs.rs20
-rw-r--r--tests/rustdoc/repr.rs154
-rw-r--r--tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs2
36 files changed, 848 insertions, 536 deletions
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 9fa7e2f1003..d24924b424a 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -262,15 +262,16 @@ impl<'tcx> V0SymbolMangler<'tcx> {
     fn print_pat(&mut self, pat: ty::Pattern<'tcx>) -> Result<(), std::fmt::Error> {
         Ok(match *pat {
             ty::PatternKind::Range { start, end } => {
-                let consts = [start, end];
-                for ct in consts {
-                    Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct).print(self)?;
-                }
+                self.push("R");
+                self.print_const(start)?;
+                self.print_const(end)?;
             }
             ty::PatternKind::Or(patterns) => {
+                self.push("O");
                 for pat in patterns {
                     self.print_pat(pat)?;
                 }
+                self.push("E");
             }
         })
     }
@@ -498,12 +499,9 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
             }
 
             ty::Pat(ty, pat) => {
-                // HACK: Represent as tuple until we have something better.
-                // HACK: constants are used in arrays, even if the types don't match.
-                self.push("T");
+                self.push("W");
                 ty.print(self)?;
                 self.print_pat(pat)?;
-                self.push("E");
             }
 
             ty::Array(ty, len) => {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index cebd25c6039..e3b53b2fe29 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -194,6 +194,9 @@ pub struct BTreeMap<
     root: Option<Root<K, V>>,
     length: usize,
     /// `ManuallyDrop` to control drop order (needs to be dropped after all the nodes).
+    // Although some of the accessory types store a copy of the allocator, the nodes do not.
+    // Because allocations will remain live as long as any copy (like this one) of the allocator
+    // is live, it's unnecessary to store the allocator in each node.
     pub(super) alloc: ManuallyDrop<A>,
     // For dropck; the `Box` avoids making the `Unpin` impl more strict than before
     _marker: PhantomData<crate::boxed::Box<(K, V), A>>,
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 2b8103c8b77..a87259e7c58 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -225,7 +225,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
     }
 
     fn from_new_leaf<A: Allocator + Clone>(leaf: Box<LeafNode<K, V>, A>) -> Self {
-        NodeRef { height: 0, node: NonNull::from(Box::leak(leaf)), _marker: PhantomData }
+        // The allocator must be dropped, not leaked.  See also `BTreeMap::alloc`.
+        let (leaf, _alloc) = Box::into_raw_with_allocator(leaf);
+        // SAFETY: the node was just allocated.
+        let node = unsafe { NonNull::new_unchecked(leaf) };
+        NodeRef { height: 0, node, _marker: PhantomData }
     }
 }
 
@@ -243,7 +247,11 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
         height: usize,
     ) -> Self {
         debug_assert!(height > 0);
-        let node = NonNull::from(Box::leak(internal)).cast();
+        // The allocator must be dropped, not leaked.  See also `BTreeMap::alloc`.
+        let (internal, _alloc) = Box::into_raw_with_allocator(internal);
+        // SAFETY: the node was just allocated.
+        let internal = unsafe { NonNull::new_unchecked(internal) };
+        let node = internal.cast();
         let mut this = NodeRef { height, node, _marker: PhantomData };
         this.borrow_mut().correct_all_childrens_parent_links();
         this
diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs
index a456d3d9e60..cb9e14f554d 100644
--- a/library/alloc/src/vec/extract_if.rs
+++ b/library/alloc/src/vec/extract_if.rs
@@ -64,27 +64,37 @@ where
     type Item = T;
 
     fn next(&mut self) -> Option<T> {
-        unsafe {
-            while self.idx < self.end {
-                let i = self.idx;
-                let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
-                let drained = (self.pred)(&mut v[i]);
-                // Update the index *after* the predicate is called. If the index
-                // is updated prior and the predicate panics, the element at this
-                // index would be leaked.
-                self.idx += 1;
-                if drained {
-                    self.del += 1;
-                    return Some(ptr::read(&v[i]));
-                } else if self.del > 0 {
-                    let del = self.del;
-                    let src: *const T = &v[i];
-                    let dst: *mut T = &mut v[i - del];
-                    ptr::copy_nonoverlapping(src, dst, 1);
+        while self.idx < self.end {
+            let i = self.idx;
+            // SAFETY:
+            //  We know that `i < self.end` from the if guard and that `self.end <= self.old_len` from
+            //  the validity of `Self`. Therefore `i` points to an element within `vec`.
+            //
+            //  Additionally, the i-th element is valid because each element is visited at most once
+            //  and it is the first time we access vec[i].
+            //
+            //  Note: we can't use `vec.get_unchecked_mut(i)` here since the precondition for that
+            //  function is that i < vec.len(), but we've set vec's length to zero.
+            let cur = unsafe { &mut *self.vec.as_mut_ptr().add(i) };
+            let drained = (self.pred)(cur);
+            // Update the index *after* the predicate is called. If the index
+            // is updated prior and the predicate panics, the element at this
+            // index would be leaked.
+            self.idx += 1;
+            if drained {
+                self.del += 1;
+                // SAFETY: We never touch this element again after returning it.
+                return Some(unsafe { ptr::read(cur) });
+            } else if self.del > 0 {
+                // SAFETY: `self.del` > 0, so the hole slot must not overlap with current element.
+                // We use copy for move, and never touch this element again.
+                unsafe {
+                    let hole_slot = self.vec.as_mut_ptr().add(i - self.del);
+                    ptr::copy_nonoverlapping(cur, hole_slot, 1);
                 }
             }
-            None
         }
+        None
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -95,14 +105,18 @@ where
 #[stable(feature = "extract_if", since = "1.87.0")]
 impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A> {
     fn drop(&mut self) {
-        unsafe {
-            if self.idx < self.old_len && self.del > 0 {
-                let ptr = self.vec.as_mut_ptr();
-                let src = ptr.add(self.idx);
-                let dst = src.sub(self.del);
-                let tail_len = self.old_len - self.idx;
-                src.copy_to(dst, tail_len);
+        if self.del > 0 {
+            // SAFETY: Trailing unchecked items must be valid since we never touch them.
+            unsafe {
+                ptr::copy(
+                    self.vec.as_ptr().add(self.idx),
+                    self.vec.as_mut_ptr().add(self.idx - self.del),
+                    self.old_len - self.idx,
+                );
             }
+        }
+        // SAFETY: After filling holes, all items are in contiguous memory.
+        unsafe {
             self.vec.set_len(self.old_len - self.del);
         }
     }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index ebdb86f98a8..694b7b2df08 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2173,9 +2173,37 @@ impl<T, A: Allocator> Vec<T, A> {
             panic!("removal index (is {index}) should be < len (is {len})");
         }
 
+        match self.try_remove(index) {
+            Some(elem) => elem,
+            None => assert_failed(index, self.len()),
+        }
+    }
+
+    /// Remove and return the element at position `index` within the vector,
+    /// shifting all elements after it to the left, or [`None`] if it does not
+    /// exist.
+    ///
+    /// Note: Because this shifts over the remaining elements, it has a
+    /// worst-case performance of *O*(*n*). If you'd like to remove
+    /// elements from the beginning of the `Vec`, consider using
+    /// [`VecDeque::pop_front`] instead.
+    ///
+    /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(vec_try_remove)]
+    /// let mut v = vec![1, 2, 3];
+    /// assert_eq!(v.try_remove(0), Some(1));
+    /// assert_eq!(v.try_remove(2), None);
+    /// ```
+    #[unstable(feature = "vec_try_remove", issue = "146954")]
+    #[rustc_confusables("delete", "take", "remove")]
+    pub fn try_remove(&mut self, index: usize) -> Option<T> {
         let len = self.len();
         if index >= len {
-            assert_failed(index, len);
+            return None;
         }
         unsafe {
             // infallible
@@ -2191,7 +2219,7 @@ impl<T, A: Allocator> Vec<T, A> {
                 ptr::copy(ptr.add(1), ptr, len - index - 1);
             }
             self.set_len(len - 1);
-            ret
+            Some(ret)
         }
     }
 
diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs
index 8c3ce156f3c..cba9883e148 100644
--- a/library/alloctests/tests/lib.rs
+++ b/library/alloctests/tests/lib.rs
@@ -41,6 +41,7 @@
 #![feature(unique_rc_arc)]
 #![feature(macro_metavar_expr_concat)]
 #![feature(vec_peek_mut)]
+#![feature(vec_try_remove)]
 #![allow(internal_features)]
 #![deny(fuzzy_provenance_casts)]
 #![deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs
index 33a34daccbf..ea334ab0f14 100644
--- a/library/alloctests/tests/vec.rs
+++ b/library/alloctests/tests/vec.rs
@@ -631,6 +631,21 @@ fn test_swap_remove_empty() {
 }
 
 #[test]
+fn test_try_remove() {
+    let mut vec = vec![1, 2, 3];
+    // We are attempting to remove vec[0] which contains 1
+    assert_eq!(vec.try_remove(0), Some(1));
+    // Now `vec` looks like: [2, 3]
+    // We will now try to remove vec[2] which does not exist
+    // This should return `None`
+    assert_eq!(vec.try_remove(2), None);
+
+    // We will try the same thing with an empty vector
+    let mut v: Vec<u8> = vec![];
+    assert!(v.try_remove(0).is_none());
+}
+
+#[test]
 fn test_move_items() {
     let vec = vec![1, 2, 3];
     let mut vec2 = vec![];
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 1b7c28bb95a..d9184e3c9c2 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -548,6 +548,18 @@ macro_rules! nonzero_integer {
         #[doc = concat!("assert_eq!(align_of::<", stringify!($Ty), ">(), align_of::<Option<", stringify!($Ty), ">>());")]
         /// ```
         ///
+        /// # Compile-time creation
+        ///
+        /// Since both [`Option::unwrap()`] and [`Option::expect()`] are `const`, it is possible to
+        /// define a new
+        #[doc = concat!("`", stringify!($Ty), "`")]
+        /// at compile time via:
+        /// ```
+        #[doc = concat!("use std::num::", stringify!($Ty), ";")]
+        ///
+        #[doc = concat!("const TEN: ", stringify!($Ty), " = ", stringify!($Ty) , r#"::new(10).expect("ten is non-zero");"#)]
+        /// ```
+        ///
         /// [null pointer optimization]: crate::option#representation
         #[$stability]
         pub type $Ty = NonZero<$Int>;
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 109942518fc..2bcc453a532 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -710,6 +710,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 [mut-ptr-type]: #mut-ptr-type
 [fn-type]: #fn-type
 [dyn-trait-type]: #dyn-trait-type
+[pattern-type]: #pattern-type
 
 > type → \
 > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[basic-type]* \
@@ -722,6 +723,7 @@ A *placeholder* may occur in circumstances where a type or const value is not re
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 
@@ -830,6 +832,23 @@ Remaining primitives are encoded as a crate production, e.g. `C4f128`.
 [fn-sig]: #fn-sig
 [abi]: #abi
 
+* `W` — A [pattern-type][pattern-tpye] `u32 is 0..100`.
+  > <span id="pattern-type">pattern-type</span> → `W` *[pattern-kind]*
+  >
+  > <span id="pattern-kind">pattern-kind</span> → \
+  > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+  > &nbsp;&nbsp; *[or-pattern-kind]*
+  >
+  > <span id="range-pattern-kind">range-pattern-kind</span> → `R` *[const]* *[const]*
+  >
+  > <span id="or-pattern-kind">or-pattern-kind</span> → `O` *[pattern-kind]* `E`
+
+  While or patterns can be nested in theory, in practice this does not happen and they are instead flattened.
+
+  Range patterns have a start and end constant that are both included in the range.
+  The end must be larger than the start (there can be no wraparound). To emulate wraparound,
+  you need to use an or pattern of the two ranges to the upper limit and from the lower limit.
+
 * `D` — A [trait object][reference-trait-object] `dyn Trait<Assoc=X> + Send + 'a`.
 
   > <span id="dyn-trait-type">dyn-trait-type</span> → `D` *[dyn-bounds]* *[lifetime]*
@@ -1139,6 +1158,7 @@ The following is a summary of all of the productions of the symbol grammar.
 > &nbsp;&nbsp; | *[mut-ptr-type]* \
 > &nbsp;&nbsp; | *[fn-type]* \
 > &nbsp;&nbsp; | *[dyn-trait-type]* \
+> &nbsp;&nbsp; | *[pattern-type]* \
 > &nbsp;&nbsp; | *[path]* \
 > &nbsp;&nbsp; | *[backref]*
 >
@@ -1152,6 +1172,14 @@ The following is a summary of all of the productions of the symbol grammar.
 > [mut-ptr-type] → `O` *[type]* \
 > [fn-type] → `F` *[fn-sig]* \
 > [dyn-trait-type] → `D` *[dyn-bounds]* *[lifetime]*
+> [pattern-type] → `W` *[pattern-kind]*
+>
+> [pattern-kind] → \
+> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[range-pattern-kind]* \
+> &nbsp;&nbsp; *[or-pattern-kind]*
+>
+> [range-pattern-kind] -> `R` *[const]* *[const]* \
+> [or-pattern-kind] -> `O` *[pattern-kind]* `E` \
 >
 > [namespace] → *[lower]* | *[upper]*
 >
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index c02c9aebe7e..f49edb2ac78 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -89,20 +89,30 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true
 This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL
 to automatically go to the first result.
 
-## `#[repr(transparent)]`: Documenting the transparent representation
+## `#[repr(...)]`: Documenting the representation of a type
+
+Generally, rustdoc only displays the representation of a given type if none of its variants are
+`#[doc(hidden)]` and if all of its fields are public and not `#[doc(hidden)]` since it's likely
+not meant to be considered part of the public ABI otherwise.
+
+Note that there's no way to overwrite that heuristic and force rustdoc to show the representation
+regardless.
+
+### `#[repr(transparent)]`
 
 You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and
 in the [Rustonomicon][repr-trans-nomicon].
 
 Since this representation is only considered part of the public ABI if the single field with non-trivial
-size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays
-the attribute if and only if the non-1-ZST field is public or at least one field is public in case all
-fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized.
+size or alignment is public and if the documentation does not state otherwise, rustdoc helpfully displays
+the attribute if and only if the non-1-ZST field is public and not `#[doc(hidden)]` or
+– in case all fields are 1-ZST fields — at least one field is public and not `#[doc(hidden)]`.
+The term *1-ZST* refers to types that are one-aligned and zero-sized.
 
 It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]`
 if one wishes to declare the representation as private even if the non-1-ZST field is public.
 However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work.
-Therefore, if you would like to do so, you should always write it down in prose independently of whether
+Therefore, if you would like to do so, you should always write that down in prose independently of whether
 you use `cfg_attr` or not.
 
 [repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bd3f4e9a6f2..ff513c71035 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -794,50 +794,6 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    /// Get a list of attributes excluding `#[repr]` to display.
-    ///
-    /// Only used by the HTML output-format.
-    fn attributes_without_repr(&self) -> Vec<String> {
-        self.attrs
-            .other_attrs
-            .iter()
-            .filter_map(|attr| match attr {
-                hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => {
-                    Some(format!("#[unsafe(link_section = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => {
-                    Some("#[unsafe(no_mangle)]".to_string())
-                }
-                hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => {
-                    Some(format!("#[unsafe(export_name = \"{name}\")]"))
-                }
-                hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => {
-                    Some("#[non_exhaustive]".to_string())
-                }
-                _ => None,
-            })
-            .collect()
-    }
-
-    /// Get a list of attributes to display on this item.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Vec<String> {
-        let mut attrs = self.attributes_without_repr();
-
-        if let Some(repr_attr) = self.repr(tcx, cache) {
-            attrs.push(repr_attr);
-        }
-        attrs
-    }
-
-    /// Returns a stringified `#[repr(...)]` attribute.
-    ///
-    /// Only used by the HTML output-format.
-    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache) -> Option<String> {
-        repr_attributes(tcx, cache, self.def_id()?, self.type_())
-    }
-
     pub fn is_doc_hidden(&self) -> bool {
         self.attrs.is_doc_hidden()
     }
@@ -847,74 +803,6 @@ impl Item {
     }
 }
 
-/// Return a string representing the `#[repr]` attribute if present.
-///
-/// Only used by the HTML output-format.
-pub(crate) fn repr_attributes(
-    tcx: TyCtxt<'_>,
-    cache: &Cache,
-    def_id: DefId,
-    item_type: ItemType,
-) -> Option<String> {
-    use rustc_abi::IntegerType;
-
-    if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
-        return None;
-    }
-    let adt = tcx.adt_def(def_id);
-    let repr = adt.repr();
-    let mut out = Vec::new();
-    if repr.c() {
-        out.push("C");
-    }
-    if repr.transparent() {
-        // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
-        // field is public in case all fields are 1-ZST fields.
-        let render_transparent = cache.document_private
-            || adt
-                .all_fields()
-                .find(|field| {
-                    let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                    tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
-                        .is_ok_and(|layout| !layout.is_1zst())
-                })
-                .map_or_else(
-                    || adt.all_fields().any(|field| field.vis.is_public()),
-                    |field| field.vis.is_public(),
-                );
-
-        if render_transparent {
-            out.push("transparent");
-        }
-    }
-    if repr.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() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
-}
-
 #[derive(Clone, Debug)]
 pub(crate) enum ItemKind {
     ExternCrateItem {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 0e06361024b..fad15573cde 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -8,6 +8,7 @@
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::{self, Display, Write};
+use std::iter;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
@@ -15,8 +16,9 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, DUMMY_SP, Span};
 
-use super::format::{self, write_str};
+use super::format;
 use crate::clean::PrimitiveType;
+use crate::display::Joined as _;
 use crate::html::escape::EscapeBodyText;
 use crate::html::macro_expansion::ExpandedCode;
 use crate::html::render::{Context, LinkFromSrc};
@@ -45,92 +47,72 @@ pub(crate) enum Tooltip {
     CompileFail,
     ShouldPanic,
     Edition(Edition),
-    None,
 }
 
 /// Highlights `src` as an inline example, returning the HTML output.
 pub(crate) fn render_example_with_highlighting(
     src: &str,
-    out: &mut String,
-    tooltip: Tooltip,
+    tooltip: Option<&Tooltip>,
     playground_button: Option<&str>,
     extra_classes: &[String],
-) {
-    write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
-    write_code(out, src, None, None, None);
-    write_footer(out, playground_button);
+) -> impl Display {
+    fmt::from_fn(move |f| {
+        write_header("rust-example-rendered", tooltip, extra_classes).fmt(f)?;
+        write_code(f, src, None, None, None);
+        write_footer(playground_button).fmt(f)
+    })
 }
 
-fn write_header(
-    out: &mut String,
-    class: &str,
-    extra_content: Option<&str>,
-    tooltip: Tooltip,
-    extra_classes: &[String],
-) {
-    write_str(
-        out,
-        format_args!(
+fn write_header(class: &str, tooltip: Option<&Tooltip>, extra_classes: &[String]) -> impl Display {
+    fmt::from_fn(move |f| {
+        write!(
+            f,
             "<div class=\"example-wrap{}\">",
-            match tooltip {
-                Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
-                Tooltip::CompileFail => " compile_fail",
-                Tooltip::ShouldPanic => " should_panic",
-                Tooltip::Edition(_) => " edition",
-                Tooltip::None => "",
-            }
-        ),
-    );
-
-    if tooltip != Tooltip::None {
-        let tooltip = fmt::from_fn(|f| match &tooltip {
-            Tooltip::IgnoreAll => f.write_str("This example is not tested"),
-            Tooltip::IgnoreSome(platforms) => {
-                f.write_str("This example is not tested on ")?;
-                match &platforms[..] {
-                    [] => unreachable!(),
-                    [platform] => f.write_str(platform)?,
-                    [first, second] => write!(f, "{first} or {second}")?,
-                    [platforms @ .., last] => {
-                        for platform in platforms {
-                            write!(f, "{platform}, ")?;
+            tooltip
+                .map(|tooltip| match tooltip {
+                    Tooltip::IgnoreAll | Tooltip::IgnoreSome(_) => " ignore",
+                    Tooltip::CompileFail => " compile_fail",
+                    Tooltip::ShouldPanic => " should_panic",
+                    Tooltip::Edition(_) => " edition",
+                })
+                .unwrap_or_default()
+        )?;
+
+        if let Some(tooltip) = tooltip {
+            let tooltip = fmt::from_fn(|f| match tooltip {
+                Tooltip::IgnoreAll => f.write_str("This example is not tested"),
+                Tooltip::IgnoreSome(platforms) => {
+                    f.write_str("This example is not tested on ")?;
+                    match &platforms[..] {
+                        [] => unreachable!(),
+                        [platform] => f.write_str(platform)?,
+                        [first, second] => write!(f, "{first} or {second}")?,
+                        [platforms @ .., last] => {
+                            for platform in platforms {
+                                write!(f, "{platform}, ")?;
+                            }
+                            write!(f, "or {last}")?;
                         }
-                        write!(f, "or {last}")?;
                     }
+                    Ok(())
                 }
-                Ok(())
-            }
-            Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
-            Tooltip::ShouldPanic => f.write_str("This example panics"),
-            Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
-            Tooltip::None => unreachable!(),
+                Tooltip::CompileFail => f.write_str("This example deliberately fails to compile"),
+                Tooltip::ShouldPanic => f.write_str("This example panics"),
+                Tooltip::Edition(edition) => write!(f, "This example runs with edition {edition}"),
+            });
+
+            write!(f, "<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>")?;
+        }
+
+        let classes = fmt::from_fn(|f| {
+            iter::once("rust")
+                .chain(Some(class).filter(|class| !class.is_empty()))
+                .chain(extra_classes.iter().map(String::as_str))
+                .joined(" ", f)
         });
-        write_str(out, format_args!("<a href=\"#\" class=\"tooltip\" title=\"{tooltip}\">ⓘ</a>"));
-    }
 
-    if let Some(extra) = extra_content {
-        out.push_str(extra);
-    }
-    if class.is_empty() {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    } else {
-        write_str(
-            out,
-            format_args!(
-                "<pre class=\"rust {class}{}{}\">",
-                if extra_classes.is_empty() { "" } else { " " },
-                extra_classes.join(" ")
-            ),
-        );
-    }
-    write_str(out, format_args!("<code>"));
+        write!(f, "<pre class=\"{classes}\"><code>")
+    })
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -577,8 +559,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut String, playground_button: Option<&str>) {
-    write_str(out, format_args!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
+fn write_footer(playground_button: Option<&str>) -> impl Display {
+    fmt::from_fn(move |f| write!(f, "</code></pre>{}</div>", playground_button.unwrap_or_default()))
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -1262,6 +1244,64 @@ fn string<W: Write>(
     }
 }
 
+fn generate_link_to_def(
+    out: &mut impl Write,
+    text_s: &str,
+    klass: Class,
+    href_context: &Option<HrefContext<'_, '_>>,
+    def_span: Span,
+    open_tag: bool,
+) -> bool {
+    if let Some(href_context) = href_context
+        && let Some(href) =
+            href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| {
+                let context = href_context.context;
+                // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
+                // one to the documentation page and one to the source definition.
+                // FIXME: currently, external items only generate a link to their documentation,
+                // a link to their definition can be generated using this:
+                // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
+                match href {
+                    LinkFromSrc::Local(span) => {
+                        context.href_from_span_relative(*span, &href_context.current_href)
+                    }
+                    LinkFromSrc::External(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(url, _, _)| url)
+                    }
+                    LinkFromSrc::Primitive(prim) => format::href_with_root_path(
+                        PrimitiveType::primitive_locations(context.tcx())[prim],
+                        context,
+                        Some(href_context.root_path),
+                    )
+                    .ok()
+                    .map(|(url, _, _)| url),
+                    LinkFromSrc::Doc(def_id) => {
+                        format::href_with_root_path(*def_id, context, Some(href_context.root_path))
+                            .ok()
+                            .map(|(doc_link, _, _)| doc_link)
+                    }
+                }
+            })
+    {
+        if !open_tag {
+            // We're already inside an element which has the same klass, no need to give it
+            // again.
+            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+        } else {
+            let klass_s = klass.as_html();
+            if klass_s.is_empty() {
+                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
+            } else {
+                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
+            }
+        }
+        return true;
+    }
+    false
+}
+
 /// This function writes `text` into `out` with some modifications depending on `klass`:
 ///
 /// * If `klass` is `None`, `text` is written into `out` with no modification.
@@ -1291,10 +1331,14 @@ fn string_without_closing_tag<T: Display>(
         return Some("</span>");
     };
 
+    let mut added_links = false;
     let mut text_s = text.to_string();
     if text_s.contains("::") {
+        let mut span = def_span.with_hi(def_span.lo());
         text_s = text_s.split("::").intersperse("::").fold(String::new(), |mut path, t| {
+            span = span.with_hi(span.hi() + BytePos(t.len() as _));
             match t {
+                "::" => write!(&mut path, "::"),
                 "self" | "Self" => write!(
                     &mut path,
                     "<span class=\"{klass}\">{t}</span>",
@@ -1307,58 +1351,24 @@ fn string_without_closing_tag<T: Display>(
                         klass = Class::KeyWord.as_html(),
                     )
                 }
-                t => write!(&mut path, "{t}"),
+                t => {
+                    if !t.is_empty()
+                        && generate_link_to_def(&mut path, t, klass, href_context, span, open_tag)
+                    {
+                        added_links = true;
+                        write!(&mut path, "</a>")
+                    } else {
+                        write!(&mut path, "{t}")
+                    }
+                }
             }
             .expect("Failed to build source HTML path");
+            span = span.with_lo(span.lo() + BytePos(t.len() as _));
             path
         });
     }
 
-    if let Some(href_context) = href_context
-        && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span)
-        && let Some(href) = {
-            let context = href_context.context;
-            // FIXME: later on, it'd be nice to provide two links (if possible) for all items:
-            // one to the documentation page and one to the source definition.
-            // FIXME: currently, external items only generate a link to their documentation,
-            // a link to their definition can be generated using this:
-            // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
-            match href {
-                LinkFromSrc::Local(span) => {
-                    context.href_from_span_relative(*span, &href_context.current_href)
-                }
-                LinkFromSrc::External(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(url, _, _)| url)
-                }
-                LinkFromSrc::Primitive(prim) => format::href_with_root_path(
-                    PrimitiveType::primitive_locations(context.tcx())[prim],
-                    context,
-                    Some(href_context.root_path),
-                )
-                .ok()
-                .map(|(url, _, _)| url),
-                LinkFromSrc::Doc(def_id) => {
-                    format::href_with_root_path(*def_id, context, Some(href_context.root_path))
-                        .ok()
-                        .map(|(doc_link, _, _)| doc_link)
-                }
-            }
-        }
-    {
-        if !open_tag {
-            // We're already inside an element which has the same klass, no need to give it
-            // again.
-            write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-        } else {
-            let klass_s = klass.as_html();
-            if klass_s.is_empty() {
-                write!(out, "<a href=\"{href}\">{text_s}").unwrap();
-            } else {
-                write!(out, "<a class=\"{klass_s}\" href=\"{href}\">{text_s}").unwrap();
-            }
-        }
+    if !added_links && generate_link_to_def(out, &text_s, klass, href_context, def_span, open_tag) {
         return Some("</a>");
     }
     if !open_tag {
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 4addf2c3c96..7065de14c8e 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -321,31 +321,34 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             ))
         });
 
-        let tooltip = if ignore == Ignore::All {
-            highlight::Tooltip::IgnoreAll
-        } else if let Ignore::Some(platforms) = ignore {
-            highlight::Tooltip::IgnoreSome(platforms)
-        } else if compile_fail {
-            highlight::Tooltip::CompileFail
-        } else if should_panic {
-            highlight::Tooltip::ShouldPanic
-        } else if explicit_edition {
-            highlight::Tooltip::Edition(edition)
-        } else {
-            highlight::Tooltip::None
+        let tooltip = {
+            use highlight::Tooltip::*;
+
+            if ignore == Ignore::All {
+                Some(IgnoreAll)
+            } else if let Ignore::Some(platforms) = ignore {
+                Some(IgnoreSome(platforms))
+            } else if compile_fail {
+                Some(CompileFail)
+            } else if should_panic {
+                Some(ShouldPanic)
+            } else if explicit_edition {
+                Some(Edition(edition))
+            } else {
+                None
+            }
         };
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
-        let mut s = String::new();
-        s.push('\n');
-
-        highlight::render_example_with_highlighting(
-            &text,
-            &mut s,
-            tooltip,
-            playground_button.as_deref(),
-            &added_classes,
+        let s = format!(
+            "\n{}",
+            highlight::render_example_with_highlighting(
+                &text,
+                tooltip.as_ref(),
+                playground_button.as_deref(),
+                &added_classes,
+            )
         );
         Some(Event::Html(s.into()))
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6d684449b6d..9a14137a6e8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -51,7 +51,9 @@ use askama::Template;
 use itertools::Either;
 use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_hir::attrs::{DeprecatedSince, Deprecation};
+use rustc_hir as hir;
+use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
 use rustc_middle::ty::print::PrintTraitRefExt;
@@ -1310,43 +1312,6 @@ fn render_assoc_item(
     })
 }
 
-struct CodeAttribute(String);
-
-fn render_code_attribute(prefix: &str, code_attr: CodeAttribute, w: &mut impl fmt::Write) {
-    write!(
-        w,
-        "<div class=\"code-attribute\">{prefix}{attr}</div>",
-        prefix = prefix,
-        attr = code_attr.0
-    )
-    .unwrap();
-}
-
-// 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 impl fmt::Write,
-    it: &clean::Item,
-    prefix: &str,
-    cx: &Context<'_>,
-) {
-    for attr in it.attributes(cx.tcx(), cx.cache()) {
-        render_code_attribute(prefix, CodeAttribute(attr), w);
-    }
-}
-
-/// used for type aliases to only render their `repr` attribute.
-fn render_repr_attributes_in_code(
-    w: &mut impl fmt::Write,
-    cx: &Context<'_>,
-    def_id: DefId,
-    item_type: ItemType,
-) {
-    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
-        render_code_attribute("", CodeAttribute(repr), w);
-    }
-}
-
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
@@ -2959,3 +2924,142 @@ fn render_call_locations<W: fmt::Write>(
 
     w.write_str("</div>")
 }
+
+fn render_attributes_in_code(
+    w: &mut impl fmt::Write,
+    item: &clean::Item,
+    prefix: &str,
+    cx: &Context<'_>,
+) {
+    for attr in &item.attrs.other_attrs {
+        let hir::Attribute::Parsed(kind) = attr else { continue };
+        let attr = match kind {
+            AttributeKind::LinkSection { name, .. } => {
+                Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
+            AttributeKind::ExportName { name, .. } => {
+                Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
+            }
+            AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
+            _ => continue,
+        };
+        render_code_attribute(prefix, attr.as_ref(), w);
+    }
+
+    if let Some(def_id) = item.def_id()
+        && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
+    {
+        render_code_attribute(prefix, &repr, w);
+    }
+}
+
+fn render_repr_attribute_in_code(w: &mut impl fmt::Write, cx: &Context<'_>, def_id: DefId) {
+    if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
+        render_code_attribute("", &repr, w);
+    }
+}
+
+fn render_code_attribute(prefix: &str, attr: &str, w: &mut impl fmt::Write) {
+    write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>").unwrap();
+}
+
+/// Compute the *public* `#[repr]` of the item given by `DefId`.
+///
+/// Read more about it here:
+/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
+fn repr_attribute<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    cache: &Cache,
+    def_id: DefId,
+) -> Option<Cow<'static, str>> {
+    let adt = match tcx.def_kind(def_id) {
+        DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
+        _ => return None,
+    };
+    let repr = adt.repr();
+
+    let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
+    let is_public_field = |field: &ty::FieldDef| {
+        (cache.document_private || field.vis.is_public()) && is_visible(field.did)
+    };
+
+    if repr.transparent() {
+        // The transparent repr is public iff the non-1-ZST field is public and visible or
+        // – in case all fields are 1-ZST fields — at least one field is public and visible.
+        let is_public = 'is_public: {
+            // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
+            let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
+
+            if !is_visible(var.def_id) {
+                break 'is_public false;
+            }
+
+            // Side note: There can only ever be one or zero non-1-ZST fields.
+            let non_1zst_field = var.fields.iter().find(|field| {
+                let ty = ty::TypingEnv::post_analysis(tcx, field.did)
+                    .as_query_input(tcx.type_of(field.did).instantiate_identity());
+                tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
+            });
+
+            match non_1zst_field {
+                Some(field) => is_public_field(field),
+                None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
+            }
+        };
+
+        // Since the transparent repr can't have any other reprs or
+        // repr modifiers beside it, we can safely return early here.
+        return is_public.then(|| "#[repr(transparent)]".into());
+    }
+
+    // Fast path which avoids looking through the variants and fields in
+    // the common case of no `#[repr]` or in the case of `#[repr(Rust)]`.
+    // FIXME: This check is not very robust / forward compatible!
+    if !repr.c()
+        && !repr.simd()
+        && repr.int.is_none()
+        && repr.pack.is_none()
+        && repr.align.is_none()
+    {
+        return None;
+    }
+
+    // The repr is public iff all components are public and visible.
+    let is_public = adt
+        .variants()
+        .iter()
+        .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
+    if !is_public {
+        return None;
+    }
+
+    let mut result = Vec::<Cow<'_, _>>::new();
+
+    if repr.c() {
+        result.push("C".into());
+    }
+    if repr.simd() {
+        result.push("simd".into());
+    }
+    if let Some(int) = repr.int {
+        let prefix = if int.is_signed() { 'i' } else { 'u' };
+        let int = match int {
+            rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
+            rustc_abi::IntegerType::Fixed(int, _) => {
+                format!("{prefix}{}", int.size().bytes() * 8)
+            }
+        };
+        result.push(int.into());
+    }
+
+    // Render modifiers last.
+    if let Some(pack) = repr.pack {
+        result.push(format!("packed({})", pack.bytes()).into());
+    }
+    if let Some(align) = repr.align {
+        result.push(format!("align({})", align.bytes()).into());
+    }
+
+    (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
+}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index afa438f2596..adfc7481c73 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -21,7 +21,7 @@ use super::{
     collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
     item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
     render_assoc_item, render_assoc_items, render_attributes_in_code, render_impl,
-    render_repr_attributes_in_code, render_rightside, render_stability_since_raw,
+    render_repr_attribute_in_code, render_rightside, render_stability_since_raw,
     render_stability_since_raw_with_extra, write_section_heading,
 };
 use crate::clean;
@@ -1555,7 +1555,7 @@ impl<'clean> DisplayEnum<'clean> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Enum);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2017,7 +2017,7 @@ impl<'a> DisplayStruct<'a> {
         wrap_item(w, |w| {
             if is_type_alias {
                 // For now the only attributes we render for type aliases are `repr` attributes.
-                render_repr_attributes_in_code(w, cx, self.def_id, ItemType::Struct);
+                render_repr_attribute_in_code(w, cx, self.def_id);
             } else {
                 render_attributes_in_code(w, it, "", cx);
             }
@@ -2371,7 +2371,7 @@ fn render_union(
     fmt::from_fn(move |mut f| {
         if is_type_alias {
             // For now the only attributes we render for type aliases are `repr` attributes.
-            render_repr_attributes_in_code(f, cx, def_id, ItemType::Union);
+            render_repr_attribute_in_code(f, cx, def_id);
         } else {
             render_attributes_in_code(f, it, "", cx);
         }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 8bc2e0bd957..ef7ce33298d 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -2,11 +2,9 @@ use std::path::{Path, PathBuf};
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{
-    ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
-};
+use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
+use rustc_hir::intravisit::{self, Visitor, VisitorExt};
+use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
@@ -67,7 +65,7 @@ struct SpanMapVisitor<'tcx> {
 
 impl SpanMapVisitor<'_> {
     /// This function is where we handle `hir::Path` elements and add them into the "span map".
-    fn handle_path(&mut self, path: &rustc_hir::Path<'_>) {
+    fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: bool) {
         match path.res {
             // FIXME: For now, we handle `DefKind` if it's not a `DefKind::TyParam`.
             // Would be nice to support them too alongside the other `DefKind`
@@ -79,24 +77,36 @@ impl SpanMapVisitor<'_> {
                     LinkFromSrc::External(def_id)
                 };
                 // In case the path ends with generics, we remove them from the span.
-                let span = path
-                    .segments
-                    .last()
-                    .map(|last| {
-                        // In `use` statements, the included item is not in the path segments.
-                        // However, it doesn't matter because you can't have generics on `use`
-                        // statements.
-                        if path.span.contains(last.ident.span) {
-                            path.span.with_hi(last.ident.span.hi())
-                        } else {
-                            path.span
-                        }
-                    })
-                    .unwrap_or(path.span);
+                let span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.segments
+                        .last()
+                        .map(|last| {
+                            // In `use` statements, the included item is not in the path segments.
+                            // However, it doesn't matter because you can't have generics on `use`
+                            // statements.
+                            if path.span.contains(last.ident.span) {
+                                path.span.with_hi(last.ident.span.hi())
+                            } else {
+                                path.span
+                            }
+                        })
+                        .unwrap_or(path.span)
+                };
                 self.matches.insert(span, link);
             }
             Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
-                self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span)));
+                let path_span = if only_use_last_segment
+                    && let Some(path_span) = path.segments.last().map(|segment| segment.ident.span)
+                {
+                    path_span
+                } else {
+                    path.span
+                };
+                self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
@@ -189,31 +199,23 @@ impl SpanMapVisitor<'_> {
             self.matches.insert(span, link);
         }
     }
+}
 
-    fn handle_pat(&mut self, p: &Pat<'_>) {
-        let mut check_qpath = |qpath, hir_id| match qpath {
-            QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
-                self.infer_id(path.hir_id, Some(hir_id), qpath.span());
-            }
-            QPath::Resolved(_, path) => self.handle_path(path),
-            _ => {}
-        };
-        match p.kind {
-            PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
-            PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
-                check_qpath(qpath, p.hir_id)
-            }
-            PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
-                check_qpath(*qpath, *hir_id)
-            }
-            PatKind::Or(pats) => {
-                for pat in pats {
-                    self.handle_pat(pat);
-                }
-            }
-            _ => {}
+// This is a reimplementation of `hir_enclosing_body_owner` which allows to fail without
+// panicking.
+fn hir_enclosing_body_owner(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<LocalDefId> {
+    for (_, node) in tcx.hir_parent_iter(hir_id) {
+        // FIXME: associated type impl items don't have an associated body, so we don't handle
+        // them currently.
+        if let Node::ImplItem(impl_item) = node
+            && matches!(impl_item.kind, rustc_hir::ImplItemKind::Type(_))
+        {
+            return None;
+        } else if let Some((def_id, _)) = node.associated_body() {
+            return Some(def_id);
         }
     }
+    None
 }
 
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
@@ -227,12 +229,42 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         if self.handle_macro(path.span) {
             return;
         }
-        self.handle_path(path);
+        self.handle_path(path, false);
         intravisit::walk_path(self, path);
     }
 
-    fn visit_pat(&mut self, p: &Pat<'tcx>) {
-        self.handle_pat(p);
+    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
+        match *qpath {
+            QPath::TypeRelative(qself, path) => {
+                if matches!(path.res, Res::Err) {
+                    let tcx = self.tcx;
+                    if let Some(body_id) = hir_enclosing_body_owner(tcx, id) {
+                        let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
+                        let path = rustc_hir::Path {
+                            // We change the span to not include parens.
+                            span: path.ident.span,
+                            res: typeck_results.qpath_res(qpath, id),
+                            segments: &[],
+                        };
+                        self.handle_path(&path, false);
+                    }
+                } else {
+                    self.infer_id(path.hir_id, Some(id), path.ident.span);
+                }
+
+                rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself));
+                self.visit_path_segment(path);
+            }
+            QPath::Resolved(maybe_qself, path) => {
+                self.handle_path(path, true);
+
+                rustc_ast::visit::visit_opt!(self, visit_ty_unambig, maybe_qself);
+                if !self.handle_macro(path.span) {
+                    intravisit::walk_path(self, path);
+                }
+            }
+            _ => {}
+        }
     }
 
     fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs
index 3e526813bb4..8b1b1e143b1 100644
--- a/src/tools/miri/tests/pass/vec.rs
+++ b/src/tools/miri/tests/pass/vec.rs
@@ -169,6 +169,15 @@ fn miri_issue_2759() {
     input.replace_range(0..0, "0");
 }
 
+/// This was skirting the edge of UB, let's make sure it remains on the sound side.
+/// Context: <https://github.com/rust-lang/rust/pull/141032>.
+fn extract_if() {
+    let mut v = vec![Box::new(0u64), Box::new(1u64)];
+    for item in v.extract_if(.., |x| **x == 0) {
+        drop(item);
+    }
+}
+
 fn main() {
     assert_eq!(vec_reallocate().len(), 5);
 
@@ -199,4 +208,5 @@ fn main() {
     swap_remove();
     reverse();
     miri_issue_2759();
+    extract_if();
 }
diff --git a/tests/codegen-llvm/pattern_type_symbols.rs b/tests/codegen-llvm/pattern_type_symbols.rs
index e86a9ef27de..a90262ff12d 100644
--- a/tests/codegen-llvm/pattern_type_symbols.rs
+++ b/tests/codegen-llvm/pattern_type_symbols.rs
@@ -16,7 +16,7 @@ pub fn bar() {
     // CHECK: call pattern_type_symbols::foo::<u32>
     // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_
     foo::<u32>();
-    // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999])>
-    // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_EEB2_
+    // CHECK: call pattern_type_symbols::foo::<u32 is 0..=999999999>
+    // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooWmRm0_m3b9ac9ff_EB2_
     foo::<NanoU32>();
 }
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index 42f2fbd93b1..de7c89a9fa3 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -459,10 +459,10 @@ pub fn safe_fn() {}
 
 #[repr(C)]
 pub struct WithGenerics<T: TraitWithNoDocblocks, S = String, E = WhoLetTheDogOut, P = i8> {
-    s: S,
-    t: T,
-    e: E,
-    p: P,
+    pub s: S,
+    pub t: T,
+    pub e: E,
+    pub p: P,
 }
 
 pub struct StructWithPublicUndocumentedFields {
diff --git a/tests/rustdoc/attribute-rendering.rs b/tests/rustdoc/attribute-rendering.rs
deleted file mode 100644
index fb40d0a9887..00000000000
--- a/tests/rustdoc/attribute-rendering.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![crate_name = "foo"]
-
-//@ has 'foo/fn.f.html'
-//@ has - //*[@'class="code-attribute"]' '#[unsafe(export_name = "f")]'
-//@ has - //*[@'class="rust item-decl"]' 'pub fn f()'
-#[unsafe(export_name = "\
-f")]
-pub fn f() {}
diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs
index 33e4e31bec6..429a42a7252 100644
--- a/tests/rustdoc/attributes.rs
+++ b/tests/rustdoc/attributes.rs
@@ -9,6 +9,18 @@ pub extern "C" fn f() {}
 #[unsafe(export_name = "bar")]
 pub extern "C" fn g() {}
 
+//@ has foo/fn.escape_special.html '//*[@class="code-attribute"]' \
+//                                 '#[unsafe(export_name = "\n\"\n")]'
+#[unsafe(export_name = "\n\"
+")]
+pub extern "C" fn escape_special() {}
+
+// issue: <https://github.com/rust-lang/rust/issues/142835>
+//@ has foo/fn.escape_html.html '//*[@class="code-attribute"]' \
+//                              '#[unsafe(export_name = "<script>alert()</script>")]'
+#[unsafe(export_name = "<script>alert()</script>")]
+pub extern "C" fn escape_html() {}
+
 //@ has foo/fn.example.html '//*[@class="code-attribute"]' '#[unsafe(link_section = ".text")]'
 #[unsafe(link_section = ".text")]
 pub extern "C" fn example() {}
diff --git a/tests/rustdoc/auxiliary/ext-repr.rs b/tests/rustdoc/auxiliary/ext-repr.rs
new file mode 100644
index 00000000000..25acaa49449
--- /dev/null
+++ b/tests/rustdoc/auxiliary/ext-repr.rs
@@ -0,0 +1,5 @@
+#[repr(i8)]
+pub enum ReprI8 {
+    Var0,
+    Var1,
+}
diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs
index 4747f8ad67c..1657b7bdc8f 100644
--- a/tests/rustdoc/inline_cross/attributes.rs
+++ b/tests/rustdoc/inline_cross/attributes.rs
@@ -1,7 +1,20 @@
+// Ensure that we render attributes on inlined cross-crate re-exported items.
+// issue: <https://github.com/rust-lang/rust/issues/144004>
+
 //@ aux-crate:attributes=attributes.rs
 //@ edition:2021
 #![crate_name = "user"]
 
-//@ has 'user/struct.NonExhaustive.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]'
+//@ has 'user/fn.no_mangle.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
+pub use attributes::no_mangle;
+
+//@ has 'user/fn.link_section.html' '//pre[@class="rust item-decl"]' \
+//                                  '#[unsafe(link_section = ".here")]'
+pub use attributes::link_section;
+
+//@ has 'user/fn.export_name.html' '//pre[@class="rust item-decl"]' \
+//                                 '#[unsafe(export_name = "exonym")]'
+pub use attributes::export_name;
+
+//@ has 'user/struct.NonExhaustive.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
 pub use attributes::NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
index c6f155d4ba5..6068d385585 100644
--- a/tests/rustdoc/inline_cross/auxiliary/attributes.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs
@@ -1,2 +1,11 @@
+#[unsafe(no_mangle)]
+pub fn no_mangle() {}
+
+#[unsafe(link_section = ".here")]
+pub fn link_section() {}
+
+#[unsafe(export_name = "exonym")]
+pub fn export_name() {}
+
 #[non_exhaustive]
 pub struct NonExhaustive;
diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs
deleted file mode 100644
index 0211e1a8658..00000000000
--- a/tests/rustdoc/inline_cross/auxiliary/repr.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-#![feature(repr_simd)]
-
-#[repr(C, align(8))]
-pub struct ReprC {
-    field: u8,
-}
-#[repr(simd, packed(2))]
-pub struct ReprSimd {
-    field: [u8; 1],
-}
-#[repr(transparent)]
-pub struct ReprTransparent {
-    pub field: u8,
-}
-#[repr(isize)]
-pub enum ReprIsize {
-    Bla,
-}
-#[repr(u8)]
-pub enum ReprU8 {
-    Bla,
-}
-
-#[repr(transparent)] // private
-pub struct ReprTransparentPrivField {
-    field: u32, // non-1-ZST field
-}
-
-#[repr(transparent)] // public
-pub struct ReprTransparentPriv1ZstFields {
-    marker0: Marker,
-    pub main: u64, // non-1-ZST field
-    marker1: Marker,
-}
-
-#[repr(transparent)] // private
-pub struct ReprTransparentPrivFieldPub1ZstFields {
-    main: [u16; 0], // non-1-ZST field
-    pub marker: Marker,
-}
-
-pub struct Marker; // 1-ZST
diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs
deleted file mode 100644
index d13e560b8d7..00000000000
--- a/tests/rustdoc/inline_cross/repr.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
-// This test ensures that the re-exported items still have the `#[repr(...)]` attribute.
-
-//@ aux-build:repr.rs
-
-#![crate_name = "foo"]
-
-extern crate repr;
-
-//@ has 'foo/struct.ReprC.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]'
-pub use repr::ReprC;
-//@ has 'foo/struct.ReprSimd.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
-pub use repr::ReprSimd;
-//@ has 'foo/struct.ReprTransparent.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparent;
-//@ has 'foo/enum.ReprIsize.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
-pub use repr::ReprIsize;
-//@ has 'foo/enum.ReprU8.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]'
-pub use repr::ReprU8;
-
-// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
-// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
-// field is public in case all fields are 1-ZST fields.
-
-//@ has 'foo/struct.ReprTransparentPrivField.html'
-//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPrivField;
-
-//@ has 'foo/struct.ReprTransparentPriv1ZstFields.html'
-//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPriv1ZstFields;
-
-//@ has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html'
-//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-pub use repr::ReprTransparentPrivFieldPub1ZstFields;
diff --git a/tests/rustdoc/jump-to-def-assoc-items.rs b/tests/rustdoc/jump-to-def-assoc-items.rs
new file mode 100644
index 00000000000..8cbf9906283
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-assoc-items.rs
@@ -0,0 +1,54 @@
+// This test ensures that patterns also get a link generated.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-assoc-items.rs.html'
+
+pub trait Trait {
+    type T;
+}
+pub trait Another {
+    type T;
+    const X: u32;
+}
+
+pub struct Foo;
+
+impl Foo {
+    pub fn new() -> Self { Foo }
+}
+
+pub struct C;
+
+impl C {
+    pub fn wat() {}
+}
+
+pub struct Bar;
+impl Trait for Bar {
+    type T = Foo;
+}
+impl Another for Bar {
+    type T = C;
+    const X: u32 = 12;
+}
+
+pub fn bar() {
+    //@ has - '//a[@href="#20"]' 'new'
+    <Bar as Trait>::T::new();
+    //@ has - '//a[@href="#26"]' 'wat'
+    <Bar as Another>::T::wat();
+
+    match 12u32 {
+        //@ has - '//a[@href="#14"]' 'X'
+        <Bar as Another>::X => {}
+        _ => {}
+    }
+}
+
+pub struct Far {
+        //@ has - '//a[@href="#10"]' 'T'
+    x: <Bar as Trait>::T,
+}
diff --git a/tests/rustdoc/jump-to-def-ice-assoc-types.rs b/tests/rustdoc/jump-to-def-ice-assoc-types.rs
new file mode 100644
index 00000000000..9915c53668f
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-ice-assoc-types.rs
@@ -0,0 +1,20 @@
+// This test ensures that associated types don't crash rustdoc jump to def.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-ice-assoc-types.rs.html'
+
+pub trait Trait {
+    type Node;
+}
+
+pub fn y<G: Trait>() {
+    struct X<G>(G);
+
+    impl<G: Trait> Trait for X<G> {
+        type Node = G::Node;
+    }
+}
diff --git a/tests/rustdoc/jump-to-def-ice.rs b/tests/rustdoc/jump-to-def-ice.rs
new file mode 100644
index 00000000000..5578b9af3d7
--- /dev/null
+++ b/tests/rustdoc/jump-to-def-ice.rs
@@ -0,0 +1,24 @@
+// This test ensures that items with no body don't panic when generating
+// jump to def links.
+
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+//@ has 'src/foo/jump-to-def-ice.rs.html'
+
+pub trait A {
+    type T;
+    type U;
+}
+
+impl A for () {
+    type T = Self::U;
+    type U = ();
+}
+
+pub trait C {
+    type X;
+}
+
+pub struct F<T: C>(pub T::X);
diff --git a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
index 61856978773..55e59f23b6f 100644
--- a/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs
@@ -8,7 +8,7 @@
 pub struct Bar;
 
 impl std::default::Default for Bar {
-    //@ has - '//a[@href="#20-22"]' 'Self::new'
+    //@ has - '//a[@href="#20-22"]' 'new'
     fn default() -> Self {
         Self::new()
     }
@@ -16,7 +16,7 @@ impl std::default::Default for Bar {
 
 //@ has - '//a[@href="#8"]' 'Bar'
 impl Bar {
-     //@ has - '//a[@href="#24-26"]' 'Self::bar'
+     //@ has - '//a[@href="#24-26"]' 'bar'
      pub fn new()-> Self {
          Self::bar()
      }
diff --git a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
index 147902b44cf..852eba208db 100644
--- a/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs
@@ -30,13 +30,13 @@ pub fn foo() -> Result<(), ()> {
 impl<T, E> fmt::Display for MyEnum<T, E> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            //@ has - '//a[@href="#12"]' 'Self::Ok'
+            //@ has - '//a[@href="#12"]' 'Ok'
             Self::Ok(_) => f.write_str("MyEnum::Ok"),
-            //@ has - '//a[@href="#13"]' 'MyEnum::Err'
+            //@ has - '//a[@href="#13"]' 'Err'
             MyEnum::Err(_) => f.write_str("MyEnum::Err"),
-            //@ has - '//a[@href="#14"]' 'Self::Some'
+            //@ has - '//a[@href="#14"]' 'Some'
             Self::Some(_) => f.write_str("MyEnum::Some"),
-            //@ has - '//a[@href="#15"]' 'Self::None'
+            //@ has - '//a[@href="#15"]' 'None'
             Self::None => f.write_str("MyEnum::None"),
         }
     }
@@ -45,7 +45,7 @@ impl<T, E> fmt::Display for MyEnum<T, E> {
 impl X {
     fn p(&self) -> &str {
         match self {
-            //@ has - '//a[@href="#19"]' 'Self::A'
+            //@ has - '//a[@href="#19"]' 'A'
             Self::A => "X::A",
         }
     }
diff --git a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
index e2f530425f0..1d6d6b8d18f 100644
--- a/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
+++ b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs
@@ -21,9 +21,10 @@ pub fn bar2<T: Read>(readable: T) {
 }
 
 pub fn bar() {
-    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'AtomicIsize::new'
+    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html"]' 'AtomicIsize'
+    //@ has - '//a[@href="{{channel}}/core/sync/atomic/struct.AtomicIsize.html#method.new"]' 'new'
     let _ = AtomicIsize::new(0);
-    //@ has - '//a[@href="#48"]' 'local_private'
+    //@ has - '//a[@href="#49"]' 'local_private'
     local_private();
 }
 
@@ -39,7 +40,7 @@ pub fn macro_call() -> Result<(), ()> {
 }
 
 pub fn variant() {
-    //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Ordering::Less'
+    //@ has - '//a[@href="{{channel}}/core/cmp/enum.Ordering.html#variant.Less"]' 'Less'
     let _ = Ordering::Less;
     //@ has - '//a[@href="{{channel}}/core/marker/struct.PhantomData.html"]' 'PhantomData'
     let _: PhantomData::<usize> = PhantomData;
diff --git a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs b/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
deleted file mode 100644
index 96fa8209cde..00000000000
--- a/tests/rustdoc/reexport/auxiliary/reexports-attrs.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#[unsafe(no_mangle)]
-pub fn f0() {}
-
-#[unsafe(link_section = ".here")]
-pub fn f1() {}
-
-#[unsafe(export_name = "f2export")]
-pub fn f2() {}
-
-#[repr(u8)]
-pub enum T0 { V1 }
-
-#[non_exhaustive]
-pub enum T1 {}
diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs
deleted file mode 100644
index aec0a11c0c6..00000000000
--- a/tests/rustdoc/reexport/reexport-attrs.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ aux-build: reexports-attrs.rs
-
-#![crate_name = "foo"]
-
-extern crate reexports_attrs;
-
-//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]'
-pub use reexports_attrs::f0;
-
-//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]'
-pub use reexports_attrs::f1;
-
-//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]'
-pub use reexports_attrs::f2;
-
-//@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]'
-pub use reexports_attrs::T0;
-
-//@ has 'foo/enum.T1.html' '//pre[@class="rust item-decl"]' '#[non_exhaustive]'
-pub use reexports_attrs::T1;
diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs
index f4f683b3d81..1e8fad6ec0a 100644
--- a/tests/rustdoc/repr.rs
+++ b/tests/rustdoc/repr.rs
@@ -1,29 +1,163 @@
-// Regression test for <https://github.com/rust-lang/rust/issues/90435>.
-// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one
-// field is public in case all fields are 1-ZST fields.
+// Test the rendering of `#[repr]` on ADTs.
+#![feature(repr_simd)] // only used for the `ReprSimd` test case
+
+// Check the "local case" (HIR cleaning) //
+
+// Don't render the default repr which is `Rust`.
+//@ has 'repr/struct.ReprDefault.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
+pub struct ReprDefault;
+
+// Don't render the `Rust` repr — even if given explicitly — since it's the default.
+//@ has 'repr/struct.ReprRust.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(Rust)]'
+#[repr(Rust)] // omitted
+pub struct ReprRust;
+
+//@ has 'repr/struct.ReprCPubFields.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // public
+pub struct ReprCPubFields {
+    pub a: u32,
+    pub b: u32,
+}
+
+//@ has 'repr/struct.ReprCPrivField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // private...
+pub struct ReprCPrivField {
+    a: u32, // ...since this is private
+    pub b: u32,
+}
+
+//@ has 'repr/enum.ReprIsize.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]'
+#[repr(isize)] // public
+pub enum ReprIsize {
+    Bla,
+}
+
+//@ has 'repr/enum.ReprU32HiddenVariant.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32)]'
+#[repr(u32)] // private...
+pub enum ReprU32HiddenVariant {
+    #[doc(hidden)]
+    Hidden, // ...since this is hidden
+    Public,
+}
+
+//@ has 'repr/struct.ReprAlignHiddenField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(align(4))]'
+#[repr(align(4))] // private...
+pub struct ReprAlignHiddenField {
+    #[doc(hidden)]
+    pub hidden: i16, // ...since this field is hidden
+}
+
+//@ has 'repr/struct.ReprSimd.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]'
+#[repr(simd, packed(2))] // public
+pub struct ReprSimd {
+    pub field: [u8; 1],
+}
+
+//@ has 'repr/enum.ReprU32Align.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u32, align(8))]'
+#[repr(u32, align(8))] // public
+pub enum ReprU32Align {
+    Variant(u16),
+}
+
+//@ has 'repr/enum.ReprCHiddenVariantField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C)]'
+#[repr(C)] // private...
+pub enum ReprCHiddenVariantField {
+    Variant { #[doc(hidden)] field: () }, //...since this field is hidden
+}
 
 //@ has 'repr/struct.ReprTransparentPrivField.html'
 //@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // private
+#[repr(transparent)] // private...
 pub struct ReprTransparentPrivField {
-    field: u32, // non-1-ZST field
+    field: u32, // ...since the non-1-ZST field is private
 }
 
 //@ has 'repr/struct.ReprTransparentPriv1ZstFields.html'
 //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // public
+#[repr(transparent)] // public...
 pub struct ReprTransparentPriv1ZstFields {
     marker0: Marker,
-    pub main: u64, // non-1-ZST field
+    pub main: u64, // ...since the non-1-ZST field is public and visible
     marker1: Marker,
+} // the two private 1-ZST fields don't matter
+
+//@ has 'repr/struct.ReprTransparentPrivFieldPub1ZstField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private...
+pub struct ReprTransparentPrivFieldPub1ZstField {
+    main: [u16; 0], // ...since the non-1-ZST field is private
+    pub marker: Marker, // this public 1-ZST field doesn't matter
 }
 
 //@ has 'repr/struct.ReprTransparentPub1ZstField.html'
 //@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
-#[repr(transparent)] // public
+#[repr(transparent)] // public...
 pub struct ReprTransparentPub1ZstField {
-    marker0: Marker,
-    pub marker1: Marker,
+    marker0: Marker, // ...since we don't have a non-1-ZST field...
+    pub marker1: Marker, // ...and this field is public and visible
+}
+
+//@ has 'repr/struct.ReprTransparentUnitStruct.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub struct ReprTransparentUnitStruct;
+
+//@ has 'repr/enum.ReprTransparentEnumUnitVariant.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public
+pub enum ReprTransparentEnumUnitVariant {
+    Variant,
+}
+
+//@ has 'repr/enum.ReprTransparentEnumHiddenUnitVariant.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private
+pub enum ReprTransparentEnumHiddenUnitVariant {
+    #[doc(hidden)] Variant(u32),
+}
+
+//@ has 'repr/enum.ReprTransparentEnumPub1ZstField.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // public...
+pub enum ReprTransparentEnumPub1ZstField {
+    Variant {
+        field: u64, // ...since the non-1-ZST field is public
+        #[doc(hidden)]
+        marker: Marker, // this hidden 1-ZST field doesn't matter
+    },
+}
+
+//@ has 'repr/enum.ReprTransparentEnumHidden1ZstField.html'
+//@ !has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]'
+#[repr(transparent)] // private...
+pub enum ReprTransparentEnumHidden1ZstField {
+    Variant {
+        #[doc(hidden)]
+        field: u64, // ...since the non-1-ZST field is public
+    },
 }
 
 struct Marker; // 1-ZST
+
+// Check the "extern case" (middle cleaning) //
+
+// Internally, HIR and middle cleaning share `#[repr]` rendering.
+// Thus we'll only test the very basics in this section.
+
+//@ aux-build: ext-repr.rs
+extern crate ext_repr as ext;
+
+// Regression test for <https://github.com/rust-lang/rust/issues/110698>.
+//@ has 'repr/enum.ReprI8.html'
+//@ has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(i8)]'
+pub use ext::ReprI8;
diff --git a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
index d701b88bf9f..a7b944fa2f6 100644
--- a/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
+++ b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs
@@ -34,7 +34,7 @@ fn babar() {}
 // The 5 links to line 23 and the line 23 itself.
 //@ count - '//pre[@class="rust"]//a[@href="#23"]' 6
 //@ has - '//pre[@class="rust"]//a[@href="../../source_code/struct.SourceCode.html"]' \
-//        'source_code::SourceCode'
+//        'SourceCode'
 pub fn foo(a: u32, b: &str, c: String, d: Foo, e: bar::Bar, f: source_code::SourceCode) {
     let x = 12;
     let y: Foo = Foo;