about summary refs log tree commit diff
path: root/src/librustdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc')
-rw-r--r--src/librustdoc/Cargo.toml4
-rw-r--r--src/librustdoc/clean/cfg.rs371
-rw-r--r--src/librustdoc/clean/inline.rs19
-rw-r--r--src/librustdoc/clean/mod.rs11
-rw-r--r--src/librustdoc/clean/types.rs209
-rw-r--r--src/librustdoc/display.rs86
-rw-r--r--src/librustdoc/doctest.rs10
-rw-r--r--src/librustdoc/doctest/rust.rs5
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/html/format.rs352
-rw-r--r--src/librustdoc/html/highlight.rs253
-rw-r--r--src/librustdoc/html/highlight/tests.rs14
-rw-r--r--src/librustdoc/html/markdown.rs45
-rw-r--r--src/librustdoc/html/render/context.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs390
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/html/render/search_index.rs63
-rw-r--r--src/librustdoc/html/render/span_map.rs186
-rw-r--r--src/librustdoc/html/render/write_shared.rs9
-rw-r--r--src/librustdoc/html/sources.rs7
-rw-r--r--src/librustdoc/html/static/js/main.js25
-rw-r--r--src/librustdoc/html/static/js/stringdex.js78
-rw-r--r--src/librustdoc/html/templates/type_layout.html5
-rw-r--r--src/librustdoc/json/conversions.rs9
-rw-r--r--src/librustdoc/lib.rs9
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/lint/html_tags.rs3
-rw-r--r--src/librustdoc/passes/mod.rs4
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs142
-rw-r--r--src/librustdoc/passes/strip_hidden.rs5
-rw-r--r--src/librustdoc/visit_ast.rs37
31 files changed, 1368 insertions, 998 deletions
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index f37a8d85361..f9c2465fb3c 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -12,7 +12,7 @@ path = "lib.rs"
 arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] }
 base64 = "0.21.7"
-indexmap = "2"
+indexmap = { version = "2", features = ["serde"] }
 itertools = "0.12"
 minifier = { version = "0.3.5", default-features = false }
 pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
@@ -21,7 +21,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.8.1"
-stringdex = { version = "0.0.1-alpha9" }
+stringdex = { version = "0.0.1-alpha10" }
 tempfile = "3"
 threadpool = "1.8.1"
 tracing = "0.1"
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index e204e1788ba..881a81b22f0 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -3,16 +3,20 @@
 // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
 // switch to use those structures instead.
 
-use std::fmt::{self, Write};
-use std::{mem, ops};
+use std::sync::Arc;
+use std::{fmt, mem, ops};
 
+use itertools::Either;
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::attrs::AttributeKind;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::ParseSess;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
+use {rustc_ast as ast, rustc_hir as hir};
 
-use crate::display::Joined as _;
+use crate::display::{Joined as _, MaybeDisplay, Wrapped};
 use crate::html::escape::Escape;
 
 #[cfg(test)]
@@ -256,6 +260,36 @@ impl Cfg {
     fn omit_preposition(&self) -> bool {
         matches!(self, Cfg::True | Cfg::False)
     }
+
+    pub(crate) fn strip_hidden(&self, hidden: &FxHashSet<Cfg>) -> Option<Self> {
+        match self {
+            Self::True | Self::False => Some(self.clone()),
+            Self::Cfg(..) => {
+                if !hidden.contains(self) {
+                    Some(self.clone())
+                } else {
+                    None
+                }
+            }
+            Self::Not(cfg) => {
+                if let Some(cfg) = cfg.strip_hidden(hidden) {
+                    Some(Self::Not(Box::new(cfg)))
+                } else {
+                    None
+                }
+            }
+            Self::Any(cfgs) => {
+                let cfgs =
+                    cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::<Vec<_>>();
+                if cfgs.is_empty() { None } else { Some(Self::Any(cfgs)) }
+            }
+            Self::All(cfgs) => {
+                let cfgs =
+                    cfgs.iter().filter_map(|cfg| cfg.strip_hidden(hidden)).collect::<Vec<_>>();
+                if cfgs.is_empty() { None } else { Some(Self::All(cfgs)) }
+            }
+        }
+    }
 }
 
 impl ops::Not for Cfg {
@@ -376,27 +410,20 @@ impl Format {
             Format::LongPlain => false,
         }
     }
+
+    fn escape(self, s: &str) -> impl fmt::Display {
+        if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) }
+    }
 }
 
 /// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
 struct Display<'a>(&'a Cfg, Format);
 
-fn write_with_opt_paren<T: fmt::Display>(
-    fmt: &mut fmt::Formatter<'_>,
-    has_paren: bool,
-    obj: T,
-) -> fmt::Result {
-    if has_paren {
-        fmt.write_char('(')?;
-    }
-    obj.fmt(fmt)?;
-    if has_paren {
-        fmt.write_char(')')?;
+impl Display<'_> {
+    fn code_wrappers(&self) -> Wrapped<&'static str> {
+        if self.1.is_html() { Wrapped::with("<code>", "</code>") } else { Wrapped::with("`", "`") }
     }
-    Ok(())
-}
 
-impl Display<'_> {
     fn display_sub_cfgs(
         &self,
         fmt: &mut fmt::Formatter<'_>,
@@ -427,20 +454,17 @@ impl Display<'_> {
             sub_cfgs
                 .iter()
                 .map(|sub_cfg| {
-                    fmt::from_fn(move |fmt| {
-                        if let Cfg::Cfg(_, Some(feat)) = sub_cfg
-                            && short_longhand
-                        {
-                            if self.1.is_html() {
-                                write!(fmt, "<code>{feat}</code>")?;
-                            } else {
-                                write!(fmt, "`{feat}`")?;
-                            }
-                        } else {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
-                        }
-                        Ok(())
-                    })
+                    if let Cfg::Cfg(_, Some(feat)) = sub_cfg
+                        && short_longhand
+                    {
+                        Either::Left(self.code_wrappers().wrap(feat))
+                    } else {
+                        Either::Right(
+                            Wrapped::with_parens()
+                                .when(!sub_cfg.is_all())
+                                .wrap(Display(sub_cfg, self.1)),
+                        )
+                    }
                 })
                 .joined(separator, f)
         })
@@ -461,9 +485,9 @@ impl fmt::Display for Display<'_> {
                 sub_cfgs
                     .iter()
                     .map(|sub_cfg| {
-                        fmt::from_fn(|fmt| {
-                            write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
-                        })
+                        Wrapped::with_parens()
+                            .when(!sub_cfg.is_all())
+                            .wrap(Display(sub_cfg, self.1))
                     })
                     .joined(separator, fmt)
             }
@@ -568,23 +592,276 @@ impl fmt::Display for Display<'_> {
                 };
                 if !human_readable.is_empty() {
                     fmt.write_str(human_readable)
-                } else if let Some(v) = value {
-                    if self.1.is_html() {
-                        write!(
-                            fmt,
-                            r#"<code>{}="{}"</code>"#,
-                            Escape(name.as_str()),
-                            Escape(v.as_str())
-                        )
+                } else {
+                    let value = value
+                        .map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))))
+                        .maybe_display();
+                    self.code_wrappers()
+                        .wrap(format_args!("{}{value}", self.1.escape(name.as_str())))
+                        .fmt(fmt)
+                }
+            }
+        }
+    }
+}
+
+/// This type keeps track of (doc) cfg information as we go down the item tree.
+#[derive(Clone, Debug)]
+pub(crate) struct CfgInfo {
+    /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
+    /// `doc(auto_cfg(show(...)))` cfgs.
+    hidden_cfg: FxHashSet<Cfg>,
+    /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
+    /// taking into account the `hidden_cfg` information.
+    current_cfg: Cfg,
+    /// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
+    auto_cfg_active: bool,
+    /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
+    /// instead we will concatenate with it. However, if it's not the case, we need to overwrite
+    /// `current_cfg`.
+    parent_is_doc_cfg: bool,
+}
+
+impl Default for CfgInfo {
+    fn default() -> Self {
+        Self {
+            hidden_cfg: FxHashSet::from_iter([
+                Cfg::Cfg(sym::test, None),
+                Cfg::Cfg(sym::doc, None),
+                Cfg::Cfg(sym::doctest, None),
+            ]),
+            current_cfg: Cfg::True,
+            auto_cfg_active: true,
+            parent_is_doc_cfg: false,
+        }
+    }
+}
+
+fn show_hide_show_conflict_error(
+    tcx: TyCtxt<'_>,
+    item_span: rustc_span::Span,
+    previous: rustc_span::Span,
+) {
+    let mut diag = tcx.sess.dcx().struct_span_err(
+        item_span,
+        format!(
+            "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
+        ),
+    );
+    diag.span_note(previous, "first change was here");
+    diag.emit();
+}
+
+/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
+///
+/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
+/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
+///
+/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
+/// and in `new_hide_attrs` arguments.
+fn handle_auto_cfg_hide_show(
+    tcx: TyCtxt<'_>,
+    cfg_info: &mut CfgInfo,
+    sub_attr: &MetaItemInner,
+    is_show: bool,
+    new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+    new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+) {
+    if let MetaItemInner::MetaItem(item) = sub_attr
+        && let MetaItemKind::List(items) = &item.kind
+    {
+        for item in items {
+            // FIXME: Report in case `Cfg::parse` reports an error?
+            if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
+                if is_show {
+                    if let Some(span) = new_hide_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
                     } else {
-                        write!(fmt, r#"`{name}="{v}"`"#)
+                        new_show_attrs.insert((key, value), item.span());
                     }
-                } else if self.1.is_html() {
-                    write!(fmt, "<code>{}</code>", Escape(name.as_str()))
+                    cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
                 } else {
-                    write!(fmt, "`{name}`")
+                    if let Some(span) = new_show_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
+                    } else {
+                        new_hide_attrs.insert((key, value), item.span());
+                    }
+                    cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
+                }
+            }
+        }
+    }
+}
+
+pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
+    attrs: I,
+    tcx: TyCtxt<'_>,
+    cfg_info: &mut CfgInfo,
+) -> Option<Arc<Cfg>> {
+    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
+        let mut iter = it.into_iter();
+        let item = iter.next()?;
+        if iter.next().is_some() {
+            return None;
+        }
+        Some(item)
+    }
+
+    fn check_changed_auto_active_status(
+        changed_auto_active_status: &mut Option<rustc_span::Span>,
+        attr: &ast::MetaItem,
+        cfg_info: &mut CfgInfo,
+        tcx: TyCtxt<'_>,
+        new_value: bool,
+    ) -> bool {
+        if let Some(first_change) = changed_auto_active_status {
+            if cfg_info.auto_cfg_active != new_value {
+                tcx.sess
+                    .dcx()
+                    .struct_span_err(
+                        vec![*first_change, attr.span],
+                        "`auto_cfg` was disabled and enabled more than once on the same item",
+                    )
+                    .emit();
+                return true;
+            }
+        } else {
+            *changed_auto_active_status = Some(attr.span);
+        }
+        cfg_info.auto_cfg_active = new_value;
+        false
+    }
+
+    let mut new_show_attrs = FxHashMap::default();
+    let mut new_hide_attrs = FxHashMap::default();
+
+    let mut doc_cfg = attrs
+        .clone()
+        .filter(|attr| attr.has_name(sym::doc))
+        .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+        .filter(|attr| attr.has_name(sym::cfg))
+        .peekable();
+    // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
+    if doc_cfg.peek().is_some() {
+        let sess = tcx.sess;
+        // We overwrite existing `cfg`.
+        if !cfg_info.parent_is_doc_cfg {
+            cfg_info.current_cfg = Cfg::True;
+            cfg_info.parent_is_doc_cfg = true;
+        }
+        for attr in doc_cfg {
+            if let Some(cfg_mi) =
+                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
+            {
+                match Cfg::parse(cfg_mi) {
+                    Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
+                    Err(e) => {
+                        sess.dcx().span_err(e.span, e.msg);
+                    }
+                }
+            }
+        }
+    } else {
+        cfg_info.parent_is_doc_cfg = false;
+    }
+
+    let mut changed_auto_active_status = None;
+
+    // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
+    for attr in attrs {
+        if let Some(ident) = attr.ident()
+            && ident.name == sym::doc
+            && let Some(attrs) = attr.meta_item_list()
+        {
+            for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
+                let MetaItemInner::MetaItem(attr) = attr else {
+                    continue;
+                };
+                match &attr.kind {
+                    MetaItemKind::Word => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                    }
+                    MetaItemKind::NameValue(lit) => {
+                        if let LitKind::Bool(value) = lit.kind {
+                            if check_changed_auto_active_status(
+                                &mut changed_auto_active_status,
+                                attr,
+                                cfg_info,
+                                tcx,
+                                value,
+                            ) {
+                                return None;
+                            }
+                        }
+                    }
+                    MetaItemKind::List(sub_attrs) => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                        for sub_attr in sub_attrs.iter() {
+                            if let Some(ident) = sub_attr.ident()
+                                && (ident.name == sym::show || ident.name == sym::hide)
+                            {
+                                handle_auto_cfg_hide_show(
+                                    tcx,
+                                    cfg_info,
+                                    &sub_attr,
+                                    ident.name == sym::show,
+                                    &mut new_show_attrs,
+                                    &mut new_hide_attrs,
+                                );
+                            }
+                        }
+                    }
                 }
             }
+        } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
+            // Treat `#[target_feature(enable = "feat")]` attributes as if they were
+            // `#[doc(cfg(target_feature = "feat"))]` attributes as well.
+            for (feature, _) in features {
+                cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
+            }
+            continue;
+        } else if !cfg_info.parent_is_doc_cfg
+            && let Some(ident) = attr.ident()
+            && matches!(ident.name, sym::cfg | sym::cfg_trace)
+            && let Some(attr) = single(attr.meta_item_list()?)
+            && let Ok(new_cfg) = Cfg::parse(&attr)
+        {
+            cfg_info.current_cfg &= new_cfg;
+        }
+    }
+
+    // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
+    // to be done here.
+    if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
+        None
+    } else if cfg_info.parent_is_doc_cfg {
+        if cfg_info.current_cfg == Cfg::True {
+            None
+        } else {
+            Some(Arc::new(cfg_info.current_cfg.clone()))
+        }
+    } else {
+        // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
+        // hidden ones afterward.
+        match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
+            None | Some(Cfg::True) => None,
+            Some(cfg) => Some(Arc::new(cfg)),
         }
     }
 }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 8461e15c6c3..8beea0580de 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -19,10 +19,10 @@ use tracing::{debug, trace};
 
 use super::{Item, extract_cfg_from_attrs};
 use crate::clean::{
-    self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item,
-    clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig,
-    clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics,
-    clean_variant_def, utils,
+    self, Attributes, CfgInfo, ImplKind, ItemId, Type, clean_bound_vars, clean_generics,
+    clean_impl_item, clean_middle_assoc_item, clean_middle_field, clean_middle_ty,
+    clean_poly_fn_sig, clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type,
+    clean_ty_generics, clean_variant_def, utils,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -409,6 +409,7 @@ pub(crate) fn merge_attrs(
     cx: &mut DocContext<'_>,
     old_attrs: &[hir::Attribute],
     new_attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
+    cfg_info: &mut CfgInfo,
 ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
     // NOTE: If we have additional attributes (from a re-export),
     // always insert them first. This ensure that re-export
@@ -423,12 +424,12 @@ pub(crate) fn merge_attrs(
             } else {
                 Attributes::from_hir(&both)
             },
-            extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            extract_cfg_from_attrs(both.iter(), cx.tcx, cfg_info),
         )
     } else {
         (
             Attributes::from_hir(old_attrs),
-            extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, cfg_info),
         )
     }
 }
@@ -604,7 +605,11 @@ pub(crate) fn build_impl(
         });
     }
 
-    let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
+    // In here, we pass an empty `CfgInfo` because the computation of `cfg` happens later, so it
+    // doesn't matter at this point.
+    //
+    // We need to pass this empty `CfgInfo` because `merge_attrs` is used when computing the `cfg`.
+    let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs, &mut CfgInfo::default());
     trace!("merged_attrs={merged_attrs:?}");
 
     trace!(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0afb969d5c8..4fd8d245089 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -58,6 +58,7 @@ use tracing::{debug, instrument};
 use utils::*;
 use {rustc_ast as ast, rustc_hir as hir};
 
+pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs};
 pub(crate) use self::types::*;
 pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
 use crate::core::DocContext;
@@ -212,18 +213,10 @@ fn generate_item_with_correct_attrs(
         // We only keep the item's attributes.
         target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
     };
-    let cfg = extract_cfg_from_attrs(
-        attrs.iter().map(move |(attr, _)| match attr {
-            Cow::Borrowed(attr) => *attr,
-            Cow::Owned(attr) => attr,
-        }),
-        cx.tcx,
-        &cx.cache.hidden_cfg,
-    );
     let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
 
     let name = renamed.or(Some(name));
-    let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg);
+    let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, None);
     // FIXME (GuillaumeGomez): Should we also make `inline_stmt_id` a `Vec` instead of an `Option`?
     item.inner.inline_stmt_id = import_ids.first().copied();
     item
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bd3f4e9a6f2..f3662a67bbe 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -467,7 +467,7 @@ impl Item {
             name,
             kind,
             Attributes::from_hir(hir_attrs),
-            extract_cfg_from_attrs(hir_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
+            None,
         )
     }
 
@@ -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 {
@@ -1014,30 +902,6 @@ impl ItemKind {
             | AttributeItem => [].iter(),
         }
     }
-
-    /// Returns `true` if this item does not appear inside an impl block.
-    pub(crate) fn is_non_assoc(&self) -> bool {
-        matches!(
-            self,
-            StructItem(_)
-                | UnionItem(_)
-                | EnumItem(_)
-                | TraitItem(_)
-                | ModuleItem(_)
-                | ExternCrateItem { .. }
-                | FunctionItem(_)
-                | TypeAliasItem(_)
-                | StaticItem(_)
-                | ConstantItem(_)
-                | TraitAliasItem(_)
-                | ForeignFunctionItem(_, _)
-                | ForeignStaticItem(_, _)
-                | ForeignTypeItem
-                | MacroItem(_)
-                | ProcMacroItem(_)
-                | PrimitiveItem(_)
-        )
-    }
 }
 
 #[derive(Clone, Debug)]
@@ -1057,75 +921,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
         .flatten()
 }
 
-pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
-    attrs: I,
-    tcx: TyCtxt<'_>,
-    hidden_cfg: &FxHashSet<Cfg>,
-) -> Option<Arc<Cfg>> {
-    let doc_cfg_active = tcx.features().doc_cfg();
-    let doc_auto_cfg_active = tcx.features().doc_auto_cfg();
-
-    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
-        let mut iter = it.into_iter();
-        let item = iter.next()?;
-        if iter.next().is_some() {
-            return None;
-        }
-        Some(item)
-    }
-
-    let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
-        let mut doc_cfg = attrs
-            .clone()
-            .filter(|attr| attr.has_name(sym::doc))
-            .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
-            .filter(|attr| attr.has_name(sym::cfg))
-            .peekable();
-        if doc_cfg.peek().is_some() && doc_cfg_active {
-            let sess = tcx.sess;
-
-            doc_cfg.fold(Cfg::True, |mut cfg, item| {
-                if let Some(cfg_mi) =
-                    item.meta_item().and_then(|item| rustc_expand::config::parse_cfg(item, sess))
-                {
-                    match Cfg::parse(cfg_mi) {
-                        Ok(new_cfg) => cfg &= new_cfg,
-                        Err(e) => {
-                            sess.dcx().span_err(e.span, e.msg);
-                        }
-                    }
-                }
-                cfg
-            })
-        } else if doc_auto_cfg_active {
-            // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
-            // `doc(cfg())` overrides `cfg()`).
-            attrs
-                .clone()
-                .filter(|attr| attr.has_name(sym::cfg_trace))
-                .filter_map(|attr| single(attr.meta_item_list()?))
-                .filter_map(|attr| Cfg::parse_without(attr.meta_item()?, hidden_cfg).ok().flatten())
-                .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
-        } else {
-            Cfg::True
-        }
-    } else {
-        Cfg::True
-    };
-
-    // treat #[target_feature(enable = "feat")] attributes as if they were
-    // #[doc(cfg(target_feature = "feat"))] attributes as well
-    if let Some(features) =
-        find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
-    {
-        for (feature, _) in features {
-            cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
-        }
-    }
-
-    if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }
-}
-
 pub(crate) trait NestedAttributesExt {
     /// Returns `true` if the attribute list contains a specific `word`
     fn has_word(self, word: Symbol) -> bool
@@ -1622,7 +1417,7 @@ impl Type {
         match (self_cleared, other_cleared) {
             // Recursive cases.
             (Type::Tuple(a), Type::Tuple(b)) => {
-                a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache))
+                a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache))
             }
             (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache),
             (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache),
diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs
index db868c5c9a8..d62ea4c3688 100644
--- a/src/librustdoc/display.rs
+++ b/src/librustdoc/display.rs
@@ -1,6 +1,6 @@
 //! Various utilities for working with [`fmt::Display`] implementations.
 
-use std::fmt::{self, Display, Formatter};
+use std::fmt::{self, Display, Formatter, FormattingOptions};
 
 pub(crate) trait Joined: IntoIterator {
     /// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
@@ -45,3 +45,87 @@ impl<T: Display> MaybeDisplay for Option<T> {
         })
     }
 }
+
+#[derive(Clone, Copy)]
+pub(crate) struct Wrapped<T> {
+    prefix: T,
+    suffix: T,
+}
+
+pub(crate) enum AngleBracket {
+    Open,
+    Close,
+}
+
+impl Display for AngleBracket {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.write_str(match (self, f.alternate()) {
+            (Self::Open, true) => "<",
+            (Self::Open, false) => "&lt;",
+            (Self::Close, true) => ">",
+            (Self::Close, false) => "&gt;",
+        })
+    }
+}
+
+impl Wrapped<AngleBracket> {
+    pub(crate) fn with_angle_brackets() -> Self {
+        Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close }
+    }
+}
+
+impl Wrapped<char> {
+    pub(crate) fn with_parens() -> Self {
+        Self { prefix: '(', suffix: ')' }
+    }
+
+    pub(crate) fn with_square_brackets() -> Self {
+        Self { prefix: '[', suffix: ']' }
+    }
+}
+
+impl<T: Display> Wrapped<T> {
+    pub(crate) fn with(prefix: T, suffix: T) -> Self {
+        Self { prefix, suffix }
+    }
+
+    pub(crate) fn when(self, if_: bool) -> Wrapped<impl Display> {
+        Wrapped {
+            prefix: if_.then_some(self.prefix).maybe_display(),
+            suffix: if_.then_some(self.suffix).maybe_display(),
+        }
+    }
+
+    pub(crate) fn wrap_fn(
+        self,
+        content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
+    ) -> impl Display {
+        fmt::from_fn(move |f| {
+            self.prefix.fmt(f)?;
+            content(f)?;
+            self.suffix.fmt(f)
+        })
+    }
+
+    pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
+        self.wrap_fn(move |f| content.fmt(f))
+    }
+}
+
+#[derive(Clone, Copy)]
+pub(crate) struct WithOpts {
+    opts: FormattingOptions,
+}
+
+impl WithOpts {
+    pub(crate) fn from(f: &Formatter<'_>) -> Self {
+        Self { opts: f.options() }
+    }
+
+    pub(crate) fn display(self, t: impl Display) -> impl Display {
+        fmt::from_fn(move |f| {
+            let mut f = f.with_options(self.opts);
+            t.fmt(&mut f)
+        })
+    }
+}
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 95bd31729de..9499258f983 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -404,11 +404,15 @@ pub(crate) fn run_tests(
             std::mem::drop(temp_dir.take());
             times.display_times();
         });
+    } else {
+        // If the first condition branch exited successfully, `test_main_with_exit_callback` will
+        // not exit the process. So to prevent displaying the times twice, we put it behind an
+        // `else` condition.
+        times.display_times();
     }
+    // We ensure temp dir destructor is called.
+    std::mem::drop(temp_dir);
     if nb_errors != 0 {
-        // We ensure temp dir destructor is called.
-        std::mem::drop(temp_dir);
-        times.display_times();
         std::process::exit(test::ERROR_EXIT_CODE);
     }
 }
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index f5ec828187a..4d3f976c2a6 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -5,7 +5,6 @@ use std::env;
 use std::sync::Arc;
 
 use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
 use rustc_hir::{self as hir, CRATE_HIR_ID, intravisit};
 use rustc_middle::hir::nested_filter;
@@ -15,7 +14,7 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, DUMMY_SP, FileName, Pos, Span, sym};
 
 use super::{DocTestVisitor, ScrapedDocTest};
-use crate::clean::{Attributes, extract_cfg_from_attrs};
+use crate::clean::{Attributes, CfgInfo, extract_cfg_from_attrs};
 use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine};
 
 struct RustCollector {
@@ -121,7 +120,7 @@ impl HirCollector<'_> {
     ) {
         let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) =
-            extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default())
+            extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &mut CfgInfo::default())
             && !cfg.matches(&self.tcx.sess.psess)
         {
             return;
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 75c848742ea..5e5592269af 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -125,8 +125,6 @@ pub(crate) struct Cache {
     ///
     /// Links are indexed by the DefId of the item they document.
     pub(crate) intra_doc_links: FxHashMap<ItemId, FxIndexSet<clean::ItemLink>>,
-    /// Cfg that have been hidden via #![doc(cfg_hide(...))]
-    pub(crate) hidden_cfg: FxHashSet<clean::cfg::Cfg>,
 
     /// Contains the list of `DefId`s which have been inlined. It is used when generating files
     /// to check if a stripped item should get its file generated or not: if it's inside a
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8c75f301841..856e637a458 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -30,17 +30,13 @@ use super::url_parts_builder::UrlPartsBuilder;
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
-use crate::display::{Joined as _, MaybeDisplay as _};
+use crate::display::{Joined as _, MaybeDisplay as _, WithOpts, Wrapped};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::render::Context;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
-pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
-    s.write_fmt(f).unwrap();
-}
-
 pub(crate) fn print_generic_bounds(
     bounds: &[clean::GenericBound],
     cx: &Context<'_>,
@@ -105,20 +101,16 @@ impl clean::GenericParamDef {
 
 impl clean::Generics {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| {
-            let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
-            if real_params.peek().is_none() {
-                return Ok(());
-            }
-
-            let real_params =
-                fmt::from_fn(|f| real_params.clone().map(|g| g.print(cx)).joined(", ", f));
-            if f.alternate() {
-                write!(f, "<{real_params:#}>")
-            } else {
-                write!(f, "&lt;{real_params}&gt;")
-            }
-        })
+        let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable();
+        if real_params.peek().is_none() {
+            None
+        } else {
+            Some(
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(move |f| real_params.clone().map(|g| g.print(cx)).joined(", ", f)),
+            )
+        }
+        .maybe_display()
     }
 }
 
@@ -151,11 +143,8 @@ fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) ->
                 Ok(())
             }
             clean::WherePredicate::EqPredicate { lhs, rhs } => {
-                if f.alternate() {
-                    write!(f, "{:#} == {:#}", lhs.print(cx), rhs.print(cx))
-                } else {
-                    write!(f, "{} == {}", lhs.print(cx), rhs.print(cx))
-                }
+                let opts = WithOpts::from(f);
+                write!(f, "{} == {}", opts.display(lhs.print(cx)), opts.display(rhs.print(cx)))
             }
         }
     })
@@ -279,13 +268,10 @@ impl clean::GenericBound {
                 ty.print(cx).fmt(f)
             }
             clean::GenericBound::Use(args) => {
-                if f.alternate() {
-                    f.write_str("use<")?;
-                } else {
-                    f.write_str("use&lt;")?;
-                }
-                args.iter().map(|arg| arg.name()).joined(", ", f)?;
-                if f.alternate() { f.write_str(">") } else { f.write_str("&gt;") }
+                f.write_str("use")?;
+                Wrapped::with_angle_brackets()
+                    .wrap_fn(|f| args.iter().map(|arg| arg.name()).joined(", ", f))
+                    .fmt(f)
             }
         })
     }
@@ -297,40 +283,29 @@ impl clean::GenericArgs {
             match self {
                 clean::GenericArgs::AngleBracketed { args, constraints } => {
                     if !args.is_empty() || !constraints.is_empty() {
-                        if f.alternate() {
-                            f.write_str("<")?;
-                        } else {
-                            f.write_str("&lt;")?;
-                        }
-
-                        [Either::Left(args), Either::Right(constraints)]
-                            .into_iter()
-                            .flat_map(Either::factor_into_iter)
-                            .map(|either| {
-                                either.map_either(
-                                    |arg| arg.print(cx),
-                                    |constraint| constraint.print(cx),
-                                )
+                        Wrapped::with_angle_brackets()
+                            .wrap_fn(|f| {
+                                [Either::Left(args), Either::Right(constraints)]
+                                    .into_iter()
+                                    .flat_map(Either::factor_into_iter)
+                                    .map(|either| {
+                                        either.map_either(
+                                            |arg| arg.print(cx),
+                                            |constraint| constraint.print(cx),
+                                        )
+                                    })
+                                    .joined(", ", f)
                             })
-                            .joined(", ", f)?;
-
-                        if f.alternate() {
-                            f.write_str(">")?;
-                        } else {
-                            f.write_str("&gt;")?;
-                        }
+                            .fmt(f)?;
                     }
                 }
                 clean::GenericArgs::Parenthesized { inputs, output } => {
-                    f.write_str("(")?;
-                    inputs.iter().map(|ty| ty.print(cx)).joined(", ", f)?;
-                    f.write_str(")")?;
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| inputs.iter().map(|ty| ty.print(cx)).joined(", ", f))
+                        .fmt(f)?;
                     if let Some(ref ty) = *output {
-                        if f.alternate() {
-                            write!(f, " -> {:#}", ty.print(cx))?;
-                        } else {
-                            write!(f, " -&gt; {}", ty.print(cx))?;
-                        }
+                        f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+                        ty.print(cx).fmt(f)?;
                     }
                 }
                 clean::GenericArgs::ReturnTypeNotation => {
@@ -834,9 +809,10 @@ fn print_higher_ranked_params_with_space(
     fmt::from_fn(move |f| {
         if !params.is_empty() {
             f.write_str(keyword)?;
-            f.write_str(if f.alternate() { "<" } else { "&lt;" })?;
-            params.iter().map(|lt| lt.print(cx)).joined(", ", f)?;
-            f.write_str(if f.alternate() { "> " } else { "&gt; " })?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| params.iter().map(|lt| lt.print(cx)).joined(", ", f))
+                .fmt(f)?;
+            f.write_char(' ')?;
         }
         Ok(())
     })
@@ -923,26 +899,23 @@ fn fmt_type(
                         f,
                         PrimitiveType::Tuple,
                         format_args!(
-                            "({})",
-                            fmt::from_fn(|f| generic_names.iter().joined(", ", f))
+                            "{}",
+                            Wrapped::with_parens()
+                                .wrap_fn(|f| generic_names.iter().joined(", ", f))
                         ),
                         cx,
                     )
                 } else {
-                    f.write_str("(")?;
-                    many.iter().map(|item| item.print(cx)).joined(", ", f)?;
-                    f.write_str(")")
+                    Wrapped::with_parens()
+                        .wrap_fn(|f| many.iter().map(|item| item.print(cx)).joined(", ", f))
+                        .fmt(f)
                 }
             }
         },
         clean::Slice(box clean::Generic(name)) => {
             primitive_link(f, PrimitiveType::Slice, format_args!("[{name}]"), cx)
         }
-        clean::Slice(t) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            write!(f, "]")
-        }
+        clean::Slice(t) => Wrapped::with_square_brackets().wrap(t.print(cx)).fmt(f),
         clean::Type::Pat(t, pat) => {
             fmt::Display::fmt(&t.print(cx), f)?;
             write!(f, " is {pat}")
@@ -953,40 +926,27 @@ fn fmt_type(
             format_args!("[{name}; {n}]", n = Escape(n)),
             cx,
         ),
-        clean::Array(t, n) => {
-            write!(f, "[")?;
-            t.print(cx).fmt(f)?;
-            if f.alternate() {
-                write!(f, "; {n}")?;
-            } else {
-                write!(f, "; ")?;
-                primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)?;
-            }
-            write!(f, "]")
-        }
-        clean::RawPointer(m, t) => {
-            let m = match m {
-                hir::Mutability::Mut => "mut",
-                hir::Mutability::Not => "const",
-            };
-
-            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
-                let ty = t.print(cx);
+        clean::Array(t, n) => Wrapped::with_square_brackets()
+            .wrap(fmt::from_fn(|f| {
+                t.print(cx).fmt(f)?;
+                f.write_str("; ")?;
                 if f.alternate() {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty:#}"),
-                        cx,
-                    )
+                    f.write_str(n)
                 } else {
-                    primitive_link(
-                        f,
-                        clean::PrimitiveType::RawPointer,
-                        format_args!("*{m} {ty}"),
-                        cx,
-                    )
+                    primitive_link(f, PrimitiveType::Array, format_args!("{n}", n = Escape(n)), cx)
                 }
+            }))
+            .fmt(f),
+        clean::RawPointer(m, t) => {
+            let m = m.ptr_str();
+
+            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
+                primitive_link(
+                    f,
+                    clean::PrimitiveType::RawPointer,
+                    format_args!("*{m} {ty}", ty = WithOpts::from(f).display(t.print(cx))),
+                    cx,
+                )
             } else {
                 primitive_link(f, clean::PrimitiveType::RawPointer, format_args!("*{m} "), cx)?;
                 t.print(cx).fmt(f)
@@ -1020,14 +980,10 @@ fn fmt_type(
                 clean::ImplTrait(ref bounds) if bounds.len() > 1 => true,
                 _ => false,
             };
-            if needs_parens {
-                f.write_str("(")?;
-            }
-            fmt_type(ty, f, use_absolute, cx)?;
-            if needs_parens {
-                f.write_str(")")?;
-            }
-            Ok(())
+            Wrapped::with_parens()
+                .when(needs_parens)
+                .wrap_fn(|f| fmt_type(ty, f, use_absolute, cx))
+                .fmt(f)
         }
         clean::ImplTrait(bounds) => {
             f.write_str("impl ")?;
@@ -1057,23 +1013,21 @@ impl clean::QPathData {
             // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719),
             // we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`).
 
-            if f.alternate() {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{:#}::", self_type.print(cx))?
-                }
+            if let Some(trait_) = trait_
+                && should_fully_qualify
+            {
+                let opts = WithOpts::from(f);
+                Wrapped::with_angle_brackets()
+                    .wrap(format_args!(
+                        "{} as {}",
+                        opts.display(self_type.print(cx)),
+                        opts.display(trait_.print(cx))
+                    ))
+                    .fmt(f)?
             } else {
-                if let Some(trait_) = trait_
-                    && should_fully_qualify
-                {
-                    write!(f, "&lt;{} as {}&gt;::", self_type.print(cx), trait_.print(cx))?
-                } else {
-                    write!(f, "{}::", self_type.print(cx))?
-                }
-            };
+                self_type.print(cx).fmt(f)?;
+            }
+            f.write_str("::")?;
             // It's pretty unsightly to look at `<A as B>::C` in output, and
             // we've got hyperlinking on our side, so try to avoid longer
             // notation as much as possible by making `C` a hyperlink to trait
@@ -1132,7 +1086,7 @@ impl clean::Impl {
 
             if let Some(ref ty) = self.trait_ {
                 if self.is_negative_trait_impl() {
-                    write!(f, "!")?;
+                    f.write_char('!')?;
                 }
                 if self.kind.is_fake_variadic()
                     && let Some(generics) = ty.generics()
@@ -1140,18 +1094,17 @@ impl clean::Impl {
                 {
                     let last = ty.last();
                     if f.alternate() {
-                        write!(f, "{last}<")?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, ">")?;
+                        write!(f, "{last}")?;
                     } else {
-                        write!(f, "{}&lt;", print_anchor(ty.def_id(), last, cx))?;
-                        self.print_type(inner_type, f, use_absolute, cx)?;
-                        write!(f, "&gt;")?;
-                    }
+                        write!(f, "{}", print_anchor(ty.def_id(), last, cx))?;
+                    };
+                    Wrapped::with_angle_brackets()
+                        .wrap_fn(|f| self.print_type(inner_type, f, use_absolute, cx))
+                        .fmt(f)?;
                 } else {
                     ty.print(cx).fmt(f)?;
                 }
-                write!(f, " for ")?;
+                f.write_str(" for ")?;
             }
 
             if let Some(ty) = self.kind.as_blanket_ty() {
@@ -1218,18 +1171,10 @@ impl clean::Impl {
             && let Ok(ty) = generics.exactly_one()
             && self.kind.is_fake_variadic()
         {
-            let wrapper = print_anchor(path.def_id(), path.last(), cx);
-            if f.alternate() {
-                write!(f, "{wrapper:#}&lt;")?;
-            } else {
-                write!(f, "{wrapper}<")?;
-            }
-            self.print_type(ty, f, use_absolute, cx)?;
-            if f.alternate() {
-                write!(f, "&gt;")?;
-            } else {
-                write!(f, ">")?;
-            }
+            print_anchor(path.def_id(), path.last(), cx).fmt(f)?;
+            Wrapped::with_angle_brackets()
+                .wrap_fn(|f| self.print_type(ty, f, use_absolute, cx))
+                .fmt(f)?;
         } else {
             fmt_type(type_, f, use_absolute, cx)?;
         }
@@ -1311,23 +1256,13 @@ impl clean::FnDecl {
     pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
         fmt::from_fn(move |f| {
             let ellipsis = if self.c_variadic { ", ..." } else { "" };
-            if f.alternate() {
-                write!(
-                    f,
-                    "({params:#}{ellipsis}){arrow:#}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            } else {
-                write!(
-                    f,
-                    "({params}{ellipsis}){arrow}",
-                    params = print_params(&self.inputs, cx),
-                    ellipsis = ellipsis,
-                    arrow = self.print_output(cx)
-                )
-            }
+            Wrapped::with_parens()
+                .wrap_fn(|f| {
+                    print_params(&self.inputs, cx).fmt(f)?;
+                    f.write_str(ellipsis)
+                })
+                .fmt(f)?;
+            self.print_output(cx).fmt(f)
         })
     }
 
@@ -1346,8 +1281,7 @@ impl clean::FnDecl {
         fmt::from_fn(move |f| {
             // First, generate the text form of the declaration, with no line wrapping, and count the bytes.
             let mut counter = WriteCounter(0);
-            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))
-                .unwrap();
+            write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) }))?;
             // If the text form was over 80 characters wide, we will line-wrap our output.
             let line_wrapping_indent =
                 if header_len + counter.0 > 80 { Some(indent) } else { None };
@@ -1365,53 +1299,56 @@ impl clean::FnDecl {
         f: &mut fmt::Formatter<'_>,
         cx: &Context<'_>,
     ) -> fmt::Result {
-        f.write_char('(')?;
-
-        if !self.inputs.is_empty() {
-            let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
+        Wrapped::with_parens()
+            .wrap_fn(|f| {
+                if !self.inputs.is_empty() {
+                    let line_wrapping_indent = line_wrapping_indent.map(|n| Indent(n + 4));
 
-            if let Some(indent) = line_wrapping_indent {
-                write!(f, "\n{indent}")?;
-            }
+                    if let Some(indent) = line_wrapping_indent {
+                        write!(f, "\n{indent}")?;
+                    }
 
-            let sep = fmt::from_fn(|f| {
-                if let Some(indent) = line_wrapping_indent {
-                    write!(f, ",\n{indent}")
-                } else {
-                    f.write_str(", ")
-                }
-            });
+                    let sep = fmt::from_fn(|f| {
+                        if let Some(indent) = line_wrapping_indent {
+                            write!(f, ",\n{indent}")
+                        } else {
+                            f.write_str(", ")
+                        }
+                    });
 
-            self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
+                    self.inputs.iter().map(|param| param.print(cx)).joined(sep, f)?;
 
-            if line_wrapping_indent.is_some() {
-                writeln!(f, ",")?
-            }
+                    if line_wrapping_indent.is_some() {
+                        writeln!(f, ",")?
+                    }
 
-            if self.c_variadic {
-                match line_wrapping_indent {
-                    None => write!(f, ", ...")?,
-                    Some(indent) => writeln!(f, "{indent}...")?,
-                };
-            }
-        }
+                    if self.c_variadic {
+                        match line_wrapping_indent {
+                            None => write!(f, ", ...")?,
+                            Some(indent) => writeln!(f, "{indent}...")?,
+                        };
+                    }
+                }
 
-        if let Some(n) = line_wrapping_indent {
-            write!(f, "{}", Indent(n))?
-        }
+                if let Some(n) = line_wrapping_indent {
+                    write!(f, "{}", Indent(n))?
+                }
 
-        f.write_char(')')?;
+                Ok(())
+            })
+            .fmt(f)?;
 
         self.print_output(cx).fmt(f)
     }
 
     fn print_output(&self, cx: &Context<'_>) -> impl Display {
-        fmt::from_fn(move |f| match &self.output {
-            clean::Tuple(tys) if tys.is_empty() => Ok(()),
-            ty if f.alternate() => {
-                write!(f, " -> {:#}", ty.print(cx))
+        fmt::from_fn(move |f| {
+            if self.output.is_unit() {
+                return Ok(());
             }
-            ty => write!(f, " -&gt; {}", ty.print(cx)),
+
+            f.write_str(if f.alternate() { " -> " } else { " -&gt; " })?;
+            self.output.print(cx).fmt(f)
         })
     }
 }
@@ -1422,10 +1359,13 @@ pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>)
             f.write_str("#[doc(hidden)] ")?;
         }
 
-        match item.visibility(cx.tcx()) {
-            None => {}
-            Some(ty::Visibility::Public) => f.write_str("pub ")?,
-            Some(ty::Visibility::Restricted(vis_did)) => {
+        let Some(vis) = item.visibility(cx.tcx()) else {
+            return Ok(());
+        };
+
+        match vis {
+            ty::Visibility::Public => f.write_str("pub ")?,
+            ty::Visibility::Restricted(vis_did) => {
                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
                 //                 However, rustdoc currently never displays a module's
                 //                 visibility, so it shouldn't matter.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 0e06361024b..1dcb4dcc3ff 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -8,17 +8,20 @@
 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};
+use rustc_span::BytePos;
 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::span_map::{DUMMY_SP, Span};
 use crate::html::render::{Context, LinkFromSrc};
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
@@ -45,92 +48,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 +560,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 +1245,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 +1332,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 +1352,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/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 2603e887bea..4d1bee9b3a1 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,6 +1,7 @@
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::create_default_session_globals_then;
+use test::Bencher;
 
 use super::{DecorationInfo, write_code};
 
@@ -81,3 +82,16 @@ let a = 4;";
         expect_file!["fixtures/decorations.html"].assert_eq(&html);
     });
 }
+
+#[bench]
+fn bench_html_highlighting(b: &mut Bencher) {
+    let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs");
+
+    create_default_session_globals_then(|| {
+        b.iter(|| {
+            let mut out = String::new();
+            write_code(&mut out, src, None, None, None);
+            out
+        });
+    });
+}
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/context.rs b/src/librustdoc/html/render/context.rs
index 5f92ab2fada..4c06d0da470 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -30,6 +30,7 @@ use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::macro_expansion::ExpandedCode;
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
+use crate::html::render::span_map::Span;
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
 use crate::html::{layout, sources, static_files};
@@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> {
 
     /// Correspondence map used to link types used in the source code pages to allow to click on
     /// links to jump to the type's definition.
-    pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
+    pub(crate) span_correspondence_map: FxHashMap<Span, LinkFromSrc>,
     pub(crate) expanded_codes: FxHashMap<BytePos, Vec<ExpandedCode>>,
     /// The [`Cache`] used during rendering.
     pub(crate) cache: Cache,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 88184c9611f..84d684e0c95 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -36,7 +36,7 @@ mod ordered_json;
 mod print_item;
 pub(crate) mod sidebar;
 mod sorted_template;
-mod span_map;
+pub(crate) mod span_map;
 mod type_layout;
 mod write_shared;
 
@@ -48,18 +48,19 @@ use std::path::PathBuf;
 use std::{fs, str};
 
 use askama::Template;
+use indexmap::IndexMap;
 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;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{Symbol, sym};
 use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName};
-use serde::ser::SerializeMap;
-use serde::{Serialize, Serializer};
 use tracing::{debug, info};
 
 pub(crate) use self::context::*;
@@ -75,7 +76,6 @@ use crate::html::escape::Escape;
 use crate::html::format::{
     Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space,
     print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
-    write_str,
 };
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
@@ -603,7 +603,12 @@ impl AllTypes {
         }
 
         fmt::from_fn(|f| {
-            f.write_str("<h1>List of all items</h1>")?;
+            f.write_str(
+                "<div class=\"main-heading\">\
+                    <h1>List of all items</h1>\
+                    <rustdoc-toolbar></rustdoc-toolbar>\
+                </div>",
+            )?;
             // Note: print_entries does not escape the title, because we know the current set of titles
             // doesn't require escaping.
             print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
@@ -1312,43 +1317,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>),
@@ -1509,12 +1477,10 @@ fn render_assoc_items_inner(
                 )
             }
         };
-        let mut impls_buf = String::new();
-        for i in &non_trait {
-            write_str(
-                &mut impls_buf,
-                format_args!(
-                    "{}",
+        let impls_buf = fmt::from_fn(|f| {
+            non_trait
+                .iter()
+                .map(|i| {
                     render_impl(
                         cx,
                         i,
@@ -1530,9 +1496,11 @@ fn render_assoc_items_inner(
                             toggle_open_by_default: true,
                         },
                     )
-                ),
-            );
-        }
+                })
+                .joined("", f)
+        })
+        .to_string();
+
         if !impls_buf.is_empty() {
             write!(
                 w,
@@ -1684,91 +1652,85 @@ fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt:
 }
 
 fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
-    let mut out = String::new();
-
     let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
 
     let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
 
-    for i in impls {
-        let impl_ = i.inner_impl();
-        if impl_.polarity != ty::ImplPolarity::Positive {
-            continue;
-        }
-
-        if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
-            // Two different types might have the same did,
-            // without actually being the same.
-            continue;
-        }
-        if let Some(trait_) = &impl_.trait_ {
-            let trait_did = trait_.def_id();
-
-            if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) {
-                if out.is_empty() {
-                    write_str(
-                        &mut out,
-                        format_args!(
-                            "<h3>Notable traits for <code>{}</code></h3>\
-                            <pre><code>",
-                            impl_.for_.print(cx)
-                        ),
-                    );
+    let out = fmt::from_fn(|f| {
+        let mut notable_impls = impls
+            .iter()
+            .map(|impl_| impl_.inner_impl())
+            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
+            .filter(|impl_| {
+                // Two different types might have the same did, without actually being the same.
+                ty.is_doc_subtype_of(&impl_.for_, cx.cache())
+            })
+            .filter_map(|impl_| {
+                if let Some(trait_) = &impl_.trait_
+                    && let trait_did = trait_.def_id()
+                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
+                    && trait_.is_notable_trait(cx.tcx())
+                {
+                    Some((impl_, trait_did))
+                } else {
+                    None
                 }
+            })
+            .peekable();
 
-                write_str(
-                    &mut out,
-                    format_args!("<div class=\"where\">{}</div>", impl_.print(false, cx)),
-                );
-                for it in &impl_.items {
-                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
-                        let empty_set = FxIndexSet::default();
-                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
-                        write_str(
-                            &mut out,
-                            format_args!(
-                                "<div class=\"where\">    {};</div>",
-                                assoc_type(
-                                    it,
-                                    &tydef.generics,
-                                    &[], // intentionally leaving out bounds
-                                    Some(&tydef.type_),
-                                    src_link,
-                                    0,
-                                    cx,
-                                )
-                            ),
-                        );
-                    }
-                }
+        let has_notable_impl = if let Some((impl_, _)) = notable_impls.peek() {
+            write!(
+                f,
+                "<h3>Notable traits for <code>{}</code></h3>\
+                <pre><code>",
+                impl_.for_.print(cx)
+            )?;
+            true
+        } else {
+            false
+        };
+
+        for (impl_, trait_did) in notable_impls {
+            write!(f, "<div class=\"where\">{}</div>", impl_.print(false, cx))?;
+            for it in &impl_.items {
+                let clean::AssocTypeItem(tydef, ..) = &it.kind else {
+                    continue;
+                };
+
+                let empty_set = FxIndexSet::default();
+                let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
+
+                write!(
+                    f,
+                    "<div class=\"where\">    {};</div>",
+                    assoc_type(
+                        it,
+                        &tydef.generics,
+                        &[], // intentionally leaving out bounds
+                        Some(&tydef.type_),
+                        src_link,
+                        0,
+                        cx,
+                    )
+                )?;
             }
         }
-    }
-    if out.is_empty() {
-        out.push_str("</code></pre>");
-    }
+
+        if !has_notable_impl {
+            f.write_str("</code></pre>")?;
+        }
+
+        Ok(())
+    })
+    .to_string();
 
     (format!("{:#}", ty.print(cx)), out)
 }
 
 fn notable_traits_json<'a>(tys: impl Iterator<Item = &'a clean::Type>, cx: &Context<'_>) -> String {
-    let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
-    mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
-    struct NotableTraitsMap(Vec<(String, String)>);
-    impl Serialize for NotableTraitsMap {
-        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-        where
-            S: Serializer,
-        {
-            let mut map = serializer.serialize_map(Some(self.0.len()))?;
-            for item in &self.0 {
-                map.serialize_entry(&item.0, &item.1)?;
-            }
-            map.end()
-        }
-    }
-    serde_json::to_string(&NotableTraitsMap(mp))
-        .expect("serialize (string, string) -> json object cannot fail")
+    let mut mp = tys.map(|ty| notable_traits_decl(ty, cx)).collect::<IndexMap<_, _>>();
+    mp.sort_unstable_keys();
+    serde_json::to_string(&mp).expect("serialize (string, string) -> json object cannot fail")
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -1842,27 +1804,19 @@ fn render_impl(
                                 document_item_info(cx, it, Some(parent))
                                     .render_into(&mut info_buffer)
                                     .unwrap();
-                                write_str(
-                                    &mut doc_buffer,
-                                    format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
-                                );
+                                doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
                                 short_documented = false;
                             } else {
                                 // In case the item isn't documented,
                                 // provide short documentation from the trait.
-                                write_str(
-                                    &mut doc_buffer,
-                                    format_args!(
-                                        "{}",
-                                        document_short(
-                                            it,
-                                            cx,
-                                            link,
-                                            parent,
-                                            rendering_params.show_def_docs,
-                                        )
-                                    ),
-                                );
+                                doc_buffer = document_short(
+                                    it,
+                                    cx,
+                                    link,
+                                    parent,
+                                    rendering_params.show_def_docs,
+                                )
+                                .to_string();
                             }
                         }
                     } else {
@@ -1870,21 +1824,14 @@ fn render_impl(
                             .render_into(&mut info_buffer)
                             .unwrap();
                         if rendering_params.show_def_docs {
-                            write_str(
-                                &mut doc_buffer,
-                                format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
-                            );
+                            doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
                             short_documented = false;
                         }
                     }
                 } else {
-                    write_str(
-                        &mut doc_buffer,
-                        format_args!(
-                            "{}",
-                            document_short(item, cx, link, parent, rendering_params.show_def_docs)
-                        ),
-                    );
+                    doc_buffer =
+                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
+                            .to_string();
                 }
             }
             let mut w = if short_documented && trait_.is_some() {
@@ -2961,3 +2908,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/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 81b38d157a8..253d9029468 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -6,6 +6,8 @@ use std::path::Path;
 
 use rustc_ast::join_path_syms;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_hir::attrs::AttributeKind;
+use rustc_hir::find_attr;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
@@ -239,6 +241,34 @@ impl SerializedSearchIndex {
         self.alias_pointers.push(alias_pointer);
         index
     }
+    /// Add potential search result to the database and return the row ID.
+    ///
+    /// The returned ID can be used to attach more data to the search result.
+    fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize {
+        let fqp = if let Some(module_path_index) = entry_data.module_path {
+            let mut fqp = self.path_data[module_path_index].as_ref().unwrap().module_path.clone();
+            fqp.push(Symbol::intern(&self.names[module_path_index]));
+            fqp.push(name);
+            fqp
+        } else {
+            vec![name]
+        };
+        // If a path with the same name already exists, but no entry does,
+        // we can fill in the entry without having to allocate a new row ID.
+        //
+        // Because paths and entries both share the same index, using the same
+        // ID saves space by making the tree smaller.
+        if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp))
+            && self.entry_data[other_path].is_none()
+            && self.descs[other_path].is_empty()
+        {
+            self.entry_data[other_path] = Some(entry_data);
+            self.descs[other_path] = desc;
+            other_path
+        } else {
+            self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None)
+        }
+    }
     fn push_path(&mut self, name: String, path_data: PathData) -> usize {
         self.push(name, Some(path_data), None, String::new(), None, None, None)
     }
@@ -1477,16 +1507,17 @@ pub(crate) fn build_index(
                     if fqp.last() != Some(&item.name) {
                         return None;
                     }
-                    let path =
-                        if item.ty == ItemType::Macro && tcx.has_attr(defid, sym::macro_export) {
-                            // `#[macro_export]` always exports to the crate root.
-                            vec![tcx.crate_name(defid.krate)]
-                        } else {
-                            if fqp.len() < 2 {
-                                return None;
-                            }
-                            fqp[..fqp.len() - 1].to_vec()
-                        };
+                    let path = if item.ty == ItemType::Macro
+                        && find_attr!(tcx.get_all_attrs(defid), AttributeKind::MacroExport { .. })
+                    {
+                        // `#[macro_export]` always exports to the crate root.
+                        vec![tcx.crate_name(defid.krate)]
+                    } else {
+                        if fqp.len() < 2 {
+                            return None;
+                        }
+                        fqp[..fqp.len() - 1].to_vec()
+                    };
                     if path == item.module_path {
                         return None;
                     }
@@ -1532,10 +1563,9 @@ pub(crate) fn build_index(
             .as_ref()
             .map(|path| serialized_index.get_id_by_module_path(path));
 
-        let new_entry_id = serialized_index.push(
-            item.name.as_str().to_string(),
-            None,
-            Some(EntryData {
+        let new_entry_id = serialized_index.add_entry(
+            item.name,
+            EntryData {
                 ty: item.ty,
                 parent: item.parent_idx,
                 trait_parent: item.trait_parent_idx,
@@ -1555,11 +1585,8 @@ pub(crate) fn build_index(
                     None
                 },
                 krate: crate_idx,
-            }),
+            },
             item.desc.to_string(),
-            None, // filled in after all the types have been indexed
-            None,
-            None,
         );
 
         // Aliases
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 8bc2e0bd957..bc9417b1bb1 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -2,19 +2,54 @@ 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;
-use rustc_span::{BytePos, ExpnKind, Span};
+use rustc_span::{BytePos, ExpnKind};
 
 use crate::clean::{self, PrimitiveType, rustc_span};
 use crate::html::sources;
 
+/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span.
+///
+/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we
+/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this
+/// one, which is much cheaper to construct.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct Span {
+    lo: BytePos,
+    hi: BytePos,
+}
+
+impl From<rustc_span::Span> for Span {
+    fn from(value: rustc_span::Span) -> Self {
+        Self { lo: value.lo(), hi: value.hi() }
+    }
+}
+
+impl Span {
+    pub(crate) fn lo(self) -> BytePos {
+        self.lo
+    }
+
+    pub(crate) fn hi(self) -> BytePos {
+        self.hi
+    }
+
+    pub(crate) fn with_lo(self, lo: BytePos) -> Self {
+        Self { lo, hi: self.hi() }
+    }
+
+    pub(crate) fn with_hi(self, hi: BytePos) -> Self {
+        Self { lo: self.lo(), hi }
+    }
+}
+
+pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) };
+
 /// This enum allows us to store two different kinds of information:
 ///
 /// In case the `span` definition comes from the same crate, we can simply get the `span` and use
@@ -67,7 +102,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,28 +114,41 @@ 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);
-                self.matches.insert(span, link);
+                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.into(), 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.into(), LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
-                self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
+                self.matches
+                    .insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p)));
             }
             Res::Err => {}
             _ => {}
@@ -117,7 +165,7 @@ impl SpanMapVisitor<'_> {
             if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
                 return;
             }
-            self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
+            self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id()));
         }
     }
 
@@ -128,7 +176,7 @@ impl SpanMapVisitor<'_> {
     /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
     /// Finally, we get the information about the macro itself (`span` if "local", `DefId`
     /// otherwise) and store it inside the span map.
-    fn handle_macro(&mut self, span: Span) -> bool {
+    fn handle_macro(&mut self, span: rustc_span::Span) -> bool {
         if !span.from_expansion() {
             return false;
         }
@@ -166,7 +214,7 @@ impl SpanMapVisitor<'_> {
         // The "call_site" includes the whole macro with its "arguments". We only want
         // the macro name.
         let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
-        self.matches.insert(new_span, link_from_src);
+        self.matches.insert(new_span.into(), link_from_src);
         true
     }
 
@@ -189,31 +237,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,15 +267,45 @@ 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: rustc_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.into());
+                }
+
+                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) {
+    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) {
         // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
         // file, we want to link to it. Otherwise no need to create a link.
         if !span.overlaps(m.spans.inner_span) {
@@ -243,8 +313,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             // name only and not all the "mod foo;".
             if let Node::Item(item) = self.tcx.hir_node(id) {
                 let (ident, _) = item.expect_mod();
-                self.matches
-                    .insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
+                self.matches.insert(
+                    ident.span.into(),
+                    LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
+                );
             }
         } else {
             // If it's a "mod foo {}", we want to look to its documentation page.
@@ -256,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
         match expr.kind {
             ExprKind::MethodCall(segment, ..) => {
-                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span)
+                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into())
             }
-            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span),
+            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()),
             _ => {
                 if self.handle_macro(expr.span) {
                     // We don't want to go deeper into the macro.
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index e37a5246a76..3a1db805d01 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -386,8 +386,13 @@ impl CratesIndexPart {
         let layout = &cx.shared.layout;
         let style_files = &cx.shared.style_files;
         const DELIMITER: &str = "\u{FFFC}"; // users are being naughty if they have this
-        let content =
-            format!("<h1>List of all crates</h1><ul class=\"all-items\">{DELIMITER}</ul>");
+        let content = format!(
+            "<div class=\"main-heading\">\
+                <h1>List of all crates</h1>\
+                <rustdoc-toolbar></rustdoc-toolbar>\
+            </div>\
+            <ul class=\"all-items\">{DELIMITER}</ul>"
+        );
         let template = layout::render(layout, &page, "", content, style_files);
         SortedTemplate::from_template(&template, DELIMITER)
             .expect("Object Replacement Character (U+FFFC) should not appear in the --index-page")
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 9c5518a780e..c79f63fbc20 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -348,7 +348,12 @@ pub(crate) fn print_src(
         highlight::write_code(
             fmt,
             s,
-            Some(highlight::HrefContext { context, file_span, root_path, current_href }),
+            Some(highlight::HrefContext {
+                context,
+                file_span: file_span.into(),
+                root_path,
+                current_href,
+            }),
             Some(decoration_info),
             Some(line_info),
         );
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 75febd6f737..3ea9de381ec 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -2227,11 +2227,18 @@ function preLoadCss(cssUrl) {
     });
 }());
 
-// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds
-// extra backline characters.
+
+// Workaround for browser-specific bugs when copying code snippets.
+//
+// * In Firefox, copying text that includes elements with `user-select: none`
+//   inserts extra blank lines.
+//   - Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
+//   - Rust issue: https://github.com/rust-lang/rust/issues/141464
 //
-// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464
-// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
+// * In Chromium-based browsers, `document.getSelection()` includes elements
+//   with `user-select: none`, causing unwanted line numbers to be copied.
+//   - Chromium issue: https://issues.chromium.org/issues/446539520
+//   - Rust issue: https://github.com/rust-lang/rust/issues/146816
 (function() {
     document.body.addEventListener("copy", event => {
         let target = nonnull(event.target);
@@ -2248,9 +2255,13 @@ function preLoadCss(cssUrl) {
         if (!isInsideCode) {
             return;
         }
-        const selection = document.getSelection();
-         // @ts-expect-error
-        nonnull(event.clipboardData).setData("text/plain", selection.toString());
+        const selection = nonnull(document.getSelection());
+        const text = Array.from({ length: selection.rangeCount }, (_, i) => {
+            const fragment = selection.getRangeAt(i).cloneContents();
+            fragment.querySelectorAll("[data-nosnippet]").forEach(el => el.remove());
+            return fragment.textContent;
+        }).join("");
+        nonnull(event.clipboardData).setData("text/plain", text);
         event.preventDefault();
     });
 }());
diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js
index 5bdc81e330e..6299576d564 100644
--- a/src/librustdoc/html/static/js/stringdex.js
+++ b/src/librustdoc/html/static/js/stringdex.js
@@ -1108,22 +1108,39 @@ function loadDatabase(hooks) {
                     const id2 = id1 + ((nodeid[4] << 8) | nodeid[5]);
                     leaves = RoaringBitmap.makeSingleton(id1)
                         .union(RoaringBitmap.makeSingleton(id2));
+                } else if (!isWhole && (nodeid[0] & 0xf0) === 0x80) {
+                    const id1 = ((nodeid[0] & 0x0f) << 16) | (nodeid[1] << 8) | nodeid[2];
+                    const id2 = id1 + ((nodeid[3] << 4) | ((nodeid[4] >> 4) & 0x0f));
+                    const id3 = id2 + (((nodeid[4] & 0x0f) << 8) | nodeid[5]);
+                    leaves = RoaringBitmap.makeSingleton(id1)
+                        .union(RoaringBitmap.makeSingleton(id2))
+                        .union(RoaringBitmap.makeSingleton(id3));
                 } else {
                     leaves = RoaringBitmap.makeSingleton(
                         (nodeid[2] << 24) | (nodeid[3] << 16) |
                         (nodeid[4] << 8) | nodeid[5],
                     );
                 }
-                const data = (nodeid[0] & 0x20) !== 0 ?
-                    Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
-                    EMPTY_UINT8;
-                newPromise = Promise.resolve(new PrefixSearchTree(
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    EMPTY_SEARCH_TREE_BRANCHES,
-                    data,
-                    isWhole ? leaves : EMPTY_BITMAP,
-                    isWhole ? EMPTY_BITMAP : leaves,
-                ));
+                if (isWhole) {
+                    const data = (nodeid[0] & 0x20) !== 0 ?
+                        Uint8Array.of(((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4)) :
+                        EMPTY_UINT8;
+                    newPromise = Promise.resolve(new PrefixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                        EMPTY_BITMAP,
+                    ));
+                } else {
+                    const data = (nodeid[0] & 0xf0) === 0x80 ? 0 : (
+                        ((nodeid[0] & 0x0f) << 4) | (nodeid[1] >> 4));
+                    newPromise = Promise.resolve(new SuffixSearchTree(
+                        EMPTY_SEARCH_TREE_BRANCHES,
+                        data,
+                        leaves,
+                    ));
+                }
             } else {
                 const hashHex = makeHexFromUint8Array(nodeid);
                 newPromise = new Promise((resolve, reject) => {
@@ -2748,6 +2765,7 @@ function loadDatabase(hooks) {
             // because that's the canonical, hashed version of the data
             let compression_tag = input[i];
             const is_pure_suffixes_only_node = (compression_tag & 0x01) !== 0;
+            let no_leaves_flag;
             if (compression_tag > 1) {
                 // compressed node
                 const is_long_compressed = (compression_tag & 0x04) !== 0;
@@ -2759,7 +2777,8 @@ function loadDatabase(hooks) {
                     compression_tag |= input[i] << 16;
                     i += 1;
                 }
-                let dlen = input[i];
+                let dlen = input[i] & 0x7F;
+                no_leaves_flag = input[i] & 0x80;
                 i += 1;
                 if (is_data_compressed) {
                     data = data_history[data_history.length - dlen - 1];
@@ -2786,10 +2805,15 @@ function loadDatabase(hooks) {
                 let whole;
                 let suffix;
                 if (is_pure_suffixes_only_node) {
-                    suffix = input[i] === 0 ?
-                        EMPTY_BITMAP1 :
-                        new RoaringBitmap(input, i);
-                    i += suffix.consumed_len_bytes;
+                    if (no_leaves_flag) {
+                        whole = EMPTY_BITMAP;
+                        suffix = EMPTY_BITMAP;
+                    } else {
+                        suffix = input[i] === 0 ?
+                            EMPTY_BITMAP1 :
+                            new RoaringBitmap(input, i);
+                        i += suffix.consumed_len_bytes;
+                    }
                     tree = new SuffixSearchTree(
                         branches,
                         dlen,
@@ -2807,7 +2831,7 @@ function loadDatabase(hooks) {
                     let ci = 0;
                     canonical[ci] = 1;
                     ci += 1;
-                    canonical[ci] = dlen;
+                    canonical[ci] = dlen | no_leaves_flag;
                     ci += 1;
                     canonical[ci] = input[coffset]; // suffix child count
                     ci += 1;
@@ -2821,10 +2845,9 @@ function loadDatabase(hooks) {
                     }
                     siphashOfBytes(canonical.subarray(0, clen), 0, 0, 0, 0, hash);
                 } else {
-                    if (input[i] === 0xff) {
+                    if (no_leaves_flag) {
                         whole = EMPTY_BITMAP;
-                        suffix = EMPTY_BITMAP1;
-                        i += 1;
+                        suffix = EMPTY_BITMAP;
                     } else {
                         whole = input[i] === 0 ?
                             EMPTY_BITMAP1 :
@@ -2856,7 +2879,7 @@ function loadDatabase(hooks) {
                     let ci = 0;
                     canonical[ci] = 0;
                     ci += 1;
-                    canonical[ci] = dlen;
+                    canonical[ci] = dlen | no_leaves_flag;
                     ci += 1;
                     canonical.set(data, ci);
                     ci += data.length;
@@ -2880,9 +2903,11 @@ function loadDatabase(hooks) {
                 }
                 hash[2] &= 0x7f;
             } else {
+                i += 1;
                 // uncompressed node
-                const dlen = input [i + 1];
-                i += 2;
+                const dlen = input[i] & 0x7F;
+                no_leaves_flag = input[i] & 0x80;
+                i += 1;
                 if (dlen === 0 || is_pure_suffixes_only_node) {
                     data = EMPTY_UINT8;
                 } else {
@@ -2897,16 +2922,15 @@ function loadDatabase(hooks) {
                 i += branches_consumed_len_bytes;
                 let whole;
                 let suffix;
-                if (is_pure_suffixes_only_node) {
+                if (no_leaves_flag) {
+                    whole = EMPTY_BITMAP;
+                    suffix = EMPTY_BITMAP;
+                } else if (is_pure_suffixes_only_node) {
                     whole = EMPTY_BITMAP;
                     suffix = input[i] === 0 ?
                         EMPTY_BITMAP1 :
                         new RoaringBitmap(input, i);
                     i += suffix.consumed_len_bytes;
-                } else if (input[i] === 0xff) {
-                    whole = EMPTY_BITMAP;
-                    suffix = EMPTY_BITMAP;
-                    i += 1;
                 } else {
                     whole = input[i] === 0 ?
                         EMPTY_BITMAP1 :
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
index 0034552bdd3..49153d58fe9 100644
--- a/src/librustdoc/html/templates/type_layout.html
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -65,5 +65,10 @@
             <strong>Note:</strong> Encountered an error during type layout; {#+ #}
             the type's layout depended on the type's layout itself. {# #}
         </p>
+        {% when Err(LayoutError::InvalidSimd {..}) %}
+        <p> {# #}
+            <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+            the vector type had zero elements or too many elements. {# #}
+        </p>
         {% endmatch %}
 </div> {# #}
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 6fe94f9d291..779e26c7b0f 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -912,12 +912,8 @@ fn maybe_from_hir_attr(
         hir::Attribute::Parsed(kind) => kind,
 
         hir::Attribute::Unparsed(_) => {
-            return Some(if attr.has_name(sym::macro_export) {
-                Attribute::MacroExport
-                // FIXME: We should handle `#[doc(hidden)]`.
-            } else {
-                other_attr(tcx, attr)
-            });
+            // FIXME: We should handle `#[doc(hidden)]`.
+            return Some(other_attr(tcx, attr));
         }
     };
 
@@ -925,6 +921,7 @@ fn maybe_from_hir_attr(
         AK::Deprecation { .. } => return None, // Handled separately into Item::deprecation.
         AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"),
 
+        AK::MacroExport { .. } => Attribute::MacroExport,
         AK::MustUse { reason, span: _ } => {
             Attribute::MustUse { reason: reason.map(|s| s.to_string()) }
         }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 9871066b9eb..d7ffb25f8bd 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -1,5 +1,4 @@
 // tidy-alphabetical-start
-#![cfg_attr(bootstrap, feature(round_char_boundary))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/",
     html_playground_url = "https://play.rust-lang.org/"
@@ -10,9 +9,11 @@
 #![feature(box_patterns)]
 #![feature(debug_closure_helpers)]
 #![feature(file_buffered)]
+#![feature(formatting_options)]
 #![feature(if_let_guard)]
 #![feature(iter_advance_by)]
 #![feature(iter_intersperse)]
+#![feature(iter_order_by)]
 #![feature(rustc_private)]
 #![feature(test)]
 #![warn(rustc::internal)]
@@ -835,8 +836,10 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) {
         config::InputMode::NoInputMergeFinalize => {
             return wrap_return(
                 dcx,
-                run_merge_finalize(render_options)
-                    .map_err(|e| format!("could not write merged cross-crate info: {e}")),
+                rustc_span::create_session_globals_then(options.edition, &[], None, || {
+                    run_merge_finalize(render_options)
+                        .map_err(|e| format!("could not write merged cross-crate info: {e}"))
+                }),
             );
         }
     };
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 0da42f38251..79d74c3c4eb 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -130,6 +130,7 @@ impl Res {
             DefKind::Static { .. } => "static",
             DefKind::Field => "field",
             DefKind::Variant | DefKind::Ctor(..) => "variant",
+            DefKind::TyAlias => "tyalias",
             // Now handle things that don't have a specific disambiguator
             _ => match kind
                 .ns()
@@ -1708,6 +1709,7 @@ impl Disambiguator {
                 "value" => NS(Namespace::ValueNS),
                 "macro" => NS(Namespace::MacroNS),
                 "prim" | "primitive" => Primitive,
+                "tyalias" | "typealias" => Kind(DefKind::TyAlias),
                 _ => return Err((format!("unknown disambiguator `{prefix}`"), 0..idx)),
             };
 
diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs
index da09117b1bb..136ff258048 100644
--- a/src/librustdoc/passes/lint/html_tags.rs
+++ b/src/librustdoc/passes/lint/html_tags.rs
@@ -364,6 +364,7 @@ impl TagParser {
             } else {
                 if !self.tag_name.is_empty() {
                     self.in_attrs = true;
+                    // range of the entire tag within dox
                     let mut r = Range { start: range.start + start_pos, end: range.start + pos };
                     if c == '>' {
                         // In case we have a tag without attribute, we can consider the span to
@@ -381,7 +382,7 @@ impl TagParser {
                             for (new_pos, c) in text[pos..].char_indices() {
                                 if !c.is_whitespace() {
                                     if c == '>' {
-                                        r.end = range.start + new_pos + 1;
+                                        r.end = range.start + pos + new_pos + 1;
                                         found = true;
                                     } else if c == '<' {
                                         self.handle_lt_in_tag(range.clone(), pos + new_pos, f);
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 475d05b7d0e..f45df8d2d0d 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -77,11 +77,11 @@ pub(crate) enum Condition {
 pub(crate) const PASSES: &[Pass] = &[
     CHECK_DOC_CFG,
     CHECK_DOC_TEST_VISIBILITY,
+    PROPAGATE_DOC_CFG,
     STRIP_ALIASED_NON_LOCAL,
     STRIP_HIDDEN,
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
-    PROPAGATE_DOC_CFG,
     PROPAGATE_STABILITY,
     COLLECT_INTRA_DOC_LINKS,
     COLLECT_TRAIT_IMPLS,
@@ -94,11 +94,11 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
     ConditionalPass::always(CHECK_DOC_CFG),
+    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(STRIP_ALIASED_NON_LOCAL),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
-    ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
     ConditionalPass::always(PROPAGATE_STABILITY),
     ConditionalPass::always(RUN_LINTS),
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index eddafa9ba8e..d5b20f2b941 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -1,12 +1,12 @@
 //! Propagates [`#[doc(cfg(...))]`](https://github.com/rust-lang/rust/issues/43781) to child items.
 
-use std::sync::Arc;
+use rustc_ast::token::{Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_hir::{AttrArgs, Attribute};
+use rustc_span::symbol::sym;
 
-use rustc_hir::def_id::LocalDefId;
-
-use crate::clean::cfg::Cfg;
 use crate::clean::inline::{load_attrs, merge_attrs};
-use crate::clean::{Crate, Item, ItemKind};
+use crate::clean::{CfgInfo, Crate, Item, ItemKind};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::passes::Pass;
@@ -18,80 +18,112 @@ pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
 };
 
 pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
-    CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
+    if cx.tcx.features().doc_cfg() {
+        CfgPropagator { cx, cfg_info: CfgInfo::default() }.fold_crate(cr)
+    } else {
+        cr
+    }
 }
 
 struct CfgPropagator<'a, 'tcx> {
-    parent_cfg: Option<Arc<Cfg>>,
-    parent: Option<LocalDefId>,
     cx: &'a mut DocContext<'tcx>,
+    cfg_info: CfgInfo,
 }
 
-impl CfgPropagator<'_, '_> {
-    // Some items need to merge their attributes with their parents' otherwise a few of them
-    // (mostly `cfg` ones) will be missing.
-    fn merge_with_parent_attributes(&mut self, item: &mut Item) {
-        let check_parent = match &item.kind {
-            // impl blocks can be in different modules with different cfg and we need to get them
-            // as well.
-            ItemKind::ImplItem(_) => false,
-            kind if kind.is_non_assoc() => true,
-            _ => return,
-        };
+/// Returns true if the provided `token` is a `cfg` ident.
+fn is_cfg_token(token: &TokenTree) -> bool {
+    // We only keep `doc(cfg)` items.
+    matches!(token, TokenTree::Token(Token { kind: TokenKind::Ident(sym::cfg, _,), .. }, _,),)
+}
 
-        let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) else {
-            return;
-        };
+/// We only want to keep `#[cfg()]` and `#[doc(cfg())]` attributes so we rebuild a vec of
+/// `TokenTree` with only the tokens we're interested into.
+fn filter_non_cfg_tokens_from_list(args_tokens: &TokenStream) -> Vec<TokenTree> {
+    let mut tokens = Vec::with_capacity(args_tokens.len());
+    let mut skip_next_delimited = false;
+    for token in args_tokens.iter() {
+        match token {
+            TokenTree::Delimited(..) => {
+                if !skip_next_delimited {
+                    tokens.push(token.clone());
+                }
+                skip_next_delimited = false;
+            }
+            token if is_cfg_token(token) => {
+                skip_next_delimited = false;
+                tokens.push(token.clone());
+            }
+            _ => {
+                skip_next_delimited = true;
+            }
+        }
+    }
+    tokens
+}
 
-        if check_parent {
-            let expected_parent = self.cx.tcx.opt_local_parent(def_id);
-            // If parents are different, it means that `item` is a reexport and we need
-            // to compute the actual `cfg` by iterating through its "real" parents.
-            if self.parent.is_some() && self.parent == expected_parent {
-                return;
+/// This function goes through the attributes list (`new_attrs`) and extract the `cfg` tokens from
+/// it and put them into `attrs`.
+fn add_only_cfg_attributes(attrs: &mut Vec<Attribute>, new_attrs: &[Attribute]) {
+    for attr in new_attrs {
+        if attr.is_doc_comment() {
+            continue;
+        }
+        let mut attr = attr.clone();
+        if let Attribute::Unparsed(ref mut normal) = attr
+            && let [ident] = &*normal.path.segments
+        {
+            let ident = ident.name;
+            if ident == sym::doc
+                && let AttrArgs::Delimited(args) = &mut normal.args
+            {
+                let tokens = filter_non_cfg_tokens_from_list(&args.tokens);
+                args.tokens = TokenStream::new(tokens);
+                attrs.push(attr);
+            } else if ident == sym::cfg_trace {
+                // If it's a `cfg()` attribute, we keep it.
+                attrs.push(attr);
             }
         }
+    }
+}
 
+impl CfgPropagator<'_, '_> {
+    // Some items need to merge their attributes with their parents' otherwise a few of them
+    // (mostly `cfg` ones) will be missing.
+    fn merge_with_parent_attributes(&mut self, item: &mut Item) {
         let mut attrs = Vec::new();
-        let mut next_def_id = def_id;
-        while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
-            attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id()));
-            next_def_id = parent_def_id;
+        // We only need to merge an item attributes with its parent's in case it's an impl as an
+        // impl might not be defined in the same module as the item it implements.
+        //
+        // Otherwise, `cfg_info` already tracks everything we need so nothing else to do!
+        if matches!(item.kind, ItemKind::ImplItem(_))
+            && let Some(mut next_def_id) = item.item_id.as_local_def_id()
+        {
+            while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
+                let x = load_attrs(self.cx, parent_def_id.to_def_id());
+                add_only_cfg_attributes(&mut attrs, x);
+                next_def_id = parent_def_id;
+            }
         }
 
-        let (_, cfg) =
-            merge_attrs(self.cx, item.attrs.other_attrs.as_slice(), Some((&attrs, None)));
+        let (_, cfg) = merge_attrs(
+            self.cx,
+            item.attrs.other_attrs.as_slice(),
+            Some((&attrs, None)),
+            &mut self.cfg_info,
+        );
         item.inner.cfg = cfg;
     }
 }
 
 impl DocFolder for CfgPropagator<'_, '_> {
     fn fold_item(&mut self, mut item: Item) -> Option<Item> {
-        let old_parent_cfg = self.parent_cfg.clone();
+        let old_cfg_info = self.cfg_info.clone();
 
         self.merge_with_parent_attributes(&mut item);
 
-        let new_cfg = match (self.parent_cfg.take(), item.inner.cfg.take()) {
-            (None, None) => None,
-            (Some(rc), None) | (None, Some(rc)) => Some(rc),
-            (Some(mut a), Some(b)) => {
-                let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
-                *Arc::make_mut(&mut a) &= b;
-                Some(a)
-            }
-        };
-        self.parent_cfg = new_cfg.clone();
-        item.inner.cfg = new_cfg;
-
-        let old_parent =
-            if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
-                self.parent.replace(def_id)
-            } else {
-                self.parent.take()
-            };
         let result = self.fold_item_recur(item);
-        self.parent_cfg = old_parent_cfg;
-        self.parent = old_parent;
+        self.cfg_info = old_cfg_info;
 
         Some(result)
     }
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 3388ae46f05..525d05b6a98 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -2,9 +2,10 @@
 
 use std::mem;
 
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
+use rustc_hir::find_attr;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
 use tracing::debug;
 
 use crate::clean::utils::inherits_doc_hidden;
@@ -114,7 +115,7 @@ impl DocFolder for Stripper<'_, '_> {
             // If the macro has the `#[macro_export]` attribute, it means it's accessible at the
             // crate level so it should be handled differently.
             clean::MacroItem(..) => {
-                i.attrs.other_attrs.iter().any(|attr| attr.has_name(sym::macro_export))
+                find_attr!(&i.attrs.other_attrs, AttributeKind::MacroExport { .. })
             }
             _ => false,
         };
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b2e4b594375..dc9889cec21 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -5,10 +5,11 @@ use std::mem;
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
+use rustc_hir::attrs::AttributeKind;
 use rustc_hir::def::{DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
 use rustc_hir::intravisit::{Visitor, walk_body, walk_item};
-use rustc_hir::{CRATE_HIR_ID, Node};
+use rustc_hir::{Node, find_attr};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -16,7 +17,6 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{Symbol, kw, sym};
 use tracing::debug;
 
-use crate::clean::cfg::Cfg;
 use crate::clean::utils::{inherits_doc_hidden, should_ignore_res};
 use crate::clean::{NestedAttributesExt, hir_attr_lists, reexport_chain};
 use crate::core;
@@ -166,7 +166,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             if !child.reexport_chain.is_empty()
                 && let Res::Def(DefKind::Macro(_), def_id) = child.res
                 && let Some(local_def_id) = def_id.as_local()
-                && self.cx.tcx.has_attr(def_id, sym::macro_export)
+                && find_attr!(self.cx.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. })
                 && inserted.insert(def_id)
             {
                 let item = self.cx.tcx.hir_expect_item(local_def_id);
@@ -177,32 +177,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             }
         }
 
-        self.cx.cache.hidden_cfg = self
-            .cx
-            .tcx
-            .hir_attrs(CRATE_HIR_ID)
-            .iter()
-            .filter(|attr| attr.has_name(sym::doc))
-            .flat_map(|attr| attr.meta_item_list().into_iter().flatten())
-            .filter(|attr| attr.has_name(sym::cfg_hide))
-            .flat_map(|attr| {
-                attr.meta_item_list()
-                    .unwrap_or(&[])
-                    .iter()
-                    .filter_map(|attr| {
-                        Cfg::parse(attr)
-                            .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
-                            .ok()
-                    })
-                    .collect::<Vec<_>>()
-            })
-            .chain([
-                Cfg::Cfg(sym::test, None),
-                Cfg::Cfg(sym::doc, None),
-                Cfg::Cfg(sym::doctest, None),
-            ])
-            .collect();
-
         self.cx.cache.exact_paths = self.exact_paths;
         top_level_module
     }
@@ -406,7 +380,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             || match item.kind {
                 hir::ItemKind::Impl(..) => true,
                 hir::ItemKind::Macro(_, _, _) => {
-                    self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
+                    find_attr!(self.cx.tcx.get_all_attrs(item.owner_id.def_id), AttributeKind::MacroExport{..})
                 }
                 _ => false,
             }
@@ -524,7 +498,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
                 let def_id = item.owner_id.to_def_id();
                 let is_macro_2_0 = !macro_def.macro_rules;
-                let nonexported = !tcx.has_attr(def_id, sym::macro_export);
+                let nonexported =
+                    !find_attr!(tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. });
 
                 if is_macro_2_0 || nonexported || self.inlining {
                     self.add_to_current_mod(item, renamed, import_id);