about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs618
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs3
-rw-r--r--compiler/rustc_errors/src/emitter.rs17
-rw-r--r--compiler/rustc_errors/src/json.rs9
-rw-r--r--compiler/rustc_errors/src/json/tests.rs3
-rw-r--r--compiler/rustc_errors/src/lib.rs8
-rw-r--r--compiler/rustc_expand/src/tests.rs3
-rw-r--r--compiler/rustc_session/src/options.rs16
-rw-r--r--compiler/rustc_session/src/session.rs18
-rw-r--r--compiler/rustc_span/src/span_encoding.rs7
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs7
-rw-r--r--library/core/src/array/drain.rs76
-rw-r--r--library/core/src/array/mod.rs256
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs14
-rw-r--r--library/core/src/iter/adapters/cloned.rs15
-rw-r--r--library/core/src/iter/adapters/map.rs15
-rw-r--r--library/core/src/iter/adapters/zip.rs9
-rw-r--r--library/core/src/iter/mod.rs1
-rw-r--r--library/core/src/iter/traits/mod.rs3
-rw-r--r--library/core/src/iter/traits/unchecked_iterator.rs36
-rw-r--r--library/core/src/ops/try_trait.rs9
-rw-r--r--library/core/src/slice/iter.rs4
-rw-r--r--library/core/src/slice/iter/macros.rs9
-rw-r--r--library/core/tests/array.rs25
-rw-r--r--library/core/tests/iter/traits/iterator.rs3
-rw-r--r--src/ci/stage-build.py19
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/librustdoc/doctest.rs5
-rw-r--r--src/librustdoc/html/highlight.rs16
-rw-r--r--src/librustdoc/html/render/mod.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css54
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css2
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css2
-rw-r--r--src/librustdoc/html/static/css/themes/light.css2
-rw-r--r--src/librustdoc/html/static/js/main.js112
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs3
-rw-r--r--src/tools/clippy/src/driver.rs1
-rw-r--r--src/tools/rustfmt/src/parse/session.rs3
-rw-r--r--tests/codegen/array-map.rs49
-rw-r--r--tests/codegen/autovectorize-f32x4.rs13
-rw-r--r--tests/rustdoc-gui/codeblock-tooltip.goml94
-rw-r--r--tests/rustdoc-gui/notable-trait.goml128
-rw-r--r--tests/rustdoc-ui/z-help.stdout1
-rw-r--r--tests/rustdoc/codeblock-title.rs2
-rw-r--r--tests/rustdoc/doc-notable_trait.rs6
-rw-r--r--tests/rustdoc/spotlight-from-dependency.rs2
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.rs4
-rw-r--r--tests/ui/diagnostic-flags/terminal_urls.stderr11
-rw-r--r--tests/ui/span/issue-107353.rs9
49 files changed, 1021 insertions, 706 deletions
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index cd60506dd80..e75d2f77dbb 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -40,84 +40,65 @@ impl MarkedAttrs {
     }
 }
 
-impl NestedMetaItem {
-    /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
-    pub fn meta_item(&self) -> Option<&MetaItem> {
-        match self {
-            NestedMetaItem::MetaItem(item) => Some(item),
-            _ => None,
-        }
-    }
+pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
 
-    /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
-    pub fn lit(&self) -> Option<&MetaItemLit> {
-        match self {
-            NestedMetaItem::Lit(lit) => Some(lit),
-            _ => None,
-        }
-    }
+#[cfg(debug_assertions)]
+static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
 
-    /// Returns `true` if this list item is a MetaItem with a name of `name`.
-    pub fn has_name(&self, name: Symbol) -> bool {
-        self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
-    }
+impl AttrIdGenerator {
+    pub fn new() -> Self {
+        // We use `(index as u32).reverse_bits()` to initialize the
+        // starting value of AttrId in each worker thread.
+        // The `index` is the index of the worker thread.
+        // This ensures that the AttrId generated in each thread is unique.
+        AttrIdGenerator(WorkerLocal::new(|index| {
+            let index: u32 = index.try_into().unwrap();
 
-    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
-    pub fn ident(&self) -> Option<Ident> {
-        self.meta_item().and_then(|meta_item| meta_item.ident())
-    }
-    pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or_else(Ident::empty).name
-    }
+            #[cfg(debug_assertions)]
+            {
+                let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
+                MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
+            }
 
-    /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
-    /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
-    pub fn value_str(&self) -> Option<Symbol> {
-        self.meta_item().and_then(|meta_item| meta_item.value_str())
+            Cell::new(index.reverse_bits())
+        }))
     }
 
-    /// Returns a name and single literal value tuple of the `MetaItem`.
-    pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
-        self.meta_item().and_then(|meta_item| {
-            meta_item.meta_item_list().and_then(|meta_item_list| {
-                if meta_item_list.len() == 1
-                    && let Some(ident) = meta_item.ident()
-                    && let Some(lit) = meta_item_list[0].lit()
-                {
-                    return Some((ident.name, lit));
-                }
-                None
-            })
-        })
-    }
+    pub fn mk_attr_id(&self) -> AttrId {
+        let id = self.0.get();
 
-    /// Gets a list of inner meta items from a list `MetaItem` type.
-    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
-        self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
-    }
+        // Ensure the assigned attr_id does not overlap the bits
+        // representing the number of threads.
+        #[cfg(debug_assertions)]
+        assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
 
-    /// Returns `true` if the variant is `MetaItem`.
-    pub fn is_meta_item(&self) -> bool {
-        self.meta_item().is_some()
+        self.0.set(id + 1);
+        AttrId::from_u32(id)
     }
+}
 
-    /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
-    pub fn is_word(&self) -> bool {
-        self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+impl Attribute {
+    pub fn get_normal_item(&self) -> &AttrItem {
+        match &self.kind {
+            AttrKind::Normal(normal) => &normal.item,
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        }
     }
 
-    /// See [`MetaItem::name_value_literal_span`].
-    pub fn name_value_literal_span(&self) -> Option<Span> {
-        self.meta_item()?.name_value_literal_span()
+    pub fn unwrap_normal_item(self) -> AttrItem {
+        match self.kind {
+            AttrKind::Normal(normal) => normal.into_inner().item,
+            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        }
     }
-}
 
-impl Attribute {
-    #[inline]
-    pub fn has_name(&self, name: Symbol) -> bool {
-        match &self.kind {
-            AttrKind::Normal(normal) => normal.item.path == name,
-            AttrKind::DocComment(..) => false,
+    /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
+    /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
+    /// a doc comment) will return `false`.
+    pub fn is_doc_comment(&self) -> bool {
+        match self.kind {
+            AttrKind::Normal(..) => false,
+            AttrKind::DocComment(..) => true,
         }
     }
 
@@ -138,17 +119,11 @@ impl Attribute {
         self.ident().unwrap_or_else(Ident::empty).name
     }
 
-    pub fn value_str(&self) -> Option<Symbol> {
-        match &self.kind {
-            AttrKind::Normal(normal) => normal.item.value_str(),
-            AttrKind::DocComment(..) => None,
-        }
-    }
-
-    pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
+    #[inline]
+    pub fn has_name(&self, name: Symbol) -> bool {
         match &self.kind {
-            AttrKind::Normal(normal) => normal.item.meta_item_list(),
-            AttrKind::DocComment(..) => None,
+            AttrKind::Normal(normal) => normal.item.path == name,
+            AttrKind::DocComment(..) => false,
         }
     }
 
@@ -159,112 +134,18 @@ impl Attribute {
             false
         }
     }
-}
 
-impl MetaItem {
-    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
-    pub fn ident(&self) -> Option<Ident> {
-        if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
-    }
-    pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or_else(Ident::empty).name
-    }
-
-    /// ```text
-    /// Example:
-    ///     #[attribute(name = "value")]
-    ///                 ^^^^^^^^^^^^^^
-    /// ```
-    pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
+    pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
         match &self.kind {
-            MetaItemKind::NameValue(v) => Some(v),
-            _ => None,
+            AttrKind::Normal(normal) => normal.item.meta_item_list(),
+            AttrKind::DocComment(..) => None,
         }
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
-        self.kind.value_str()
-    }
-
-    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
         match &self.kind {
-            MetaItemKind::List(l) => Some(&**l),
-            _ => None,
-        }
-    }
-
-    pub fn is_word(&self) -> bool {
-        matches!(self.kind, MetaItemKind::Word)
-    }
-
-    pub fn has_name(&self, name: Symbol) -> bool {
-        self.path == name
-    }
-
-    /// This is used in case you want the value span instead of the whole attribute. Example:
-    ///
-    /// ```text
-    /// #[doc(alias = "foo")]
-    /// ```
-    ///
-    /// In here, it'll return a span for `"foo"`.
-    pub fn name_value_literal_span(&self) -> Option<Span> {
-        Some(self.name_value_literal()?.span)
-    }
-}
-
-impl AttrArgsEq {
-    fn value_str(&self) -> Option<Symbol> {
-        match self {
-            AttrArgsEq::Ast(expr) => match expr.kind {
-                ExprKind::Lit(token_lit) => {
-                    LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
-                }
-                _ => None,
-            },
-            AttrArgsEq::Hir(lit) => lit.kind.str(),
-        }
-    }
-}
-
-impl AttrItem {
-    pub fn span(&self) -> Span {
-        self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
-    }
-
-    pub fn meta(&self, span: Span) -> Option<MetaItem> {
-        Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
-    }
-
-    pub fn meta_kind(&self) -> Option<MetaItemKind> {
-        MetaItemKind::from_attr_args(&self.args)
-    }
-
-    fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
-        match &self.args {
-            AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
-                MetaItemKind::list_from_tokens(args.tokens.clone())
-            }
-            AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
-        }
-    }
-
-    fn value_str(&self) -> Option<Symbol> {
-        match &self.args {
-            AttrArgs::Eq(_, args) => args.value_str(),
-            AttrArgs::Delimited(_) | AttrArgs::Empty => None,
-        }
-    }
-}
-
-impl Attribute {
-    /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
-    /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
-    /// a doc comment) will return `false`.
-    pub fn is_doc_comment(&self) -> bool {
-        match self.kind {
-            AttrKind::Normal(..) => false,
-            AttrKind::DocComment(..) => true,
+            AttrKind::Normal(normal) => normal.item.value_str(),
+            AttrKind::DocComment(..) => None,
         }
     }
 
@@ -299,20 +180,6 @@ impl Attribute {
         self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
     }
 
-    pub fn get_normal_item(&self) -> &AttrItem {
-        match &self.kind {
-            AttrKind::Normal(normal) => &normal.item,
-            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
-        }
-    }
-
-    pub fn unwrap_normal_item(self) -> AttrItem {
-        match self.kind {
-            AttrKind::Normal(normal) => normal.into_inner().item,
-            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
-        }
-    }
-
     /// Extracts the MetaItem from inside this Attribute.
     pub fn meta(&self) -> Option<MetaItem> {
         match &self.kind {
@@ -344,130 +211,102 @@ impl Attribute {
     }
 }
 
-pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
-
-#[cfg(debug_assertions)]
-static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
-
-impl AttrIdGenerator {
-    pub fn new() -> Self {
-        // We use `(index as u32).reverse_bits()` to initialize the
-        // starting value of AttrId in each worker thread.
-        // The `index` is the index of the worker thread.
-        // This ensures that the AttrId generated in each thread is unique.
-        AttrIdGenerator(WorkerLocal::new(|index| {
-            let index: u32 = index.try_into().unwrap();
+impl AttrItem {
+    pub fn span(&self) -> Span {
+        self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
+    }
 
-            #[cfg(debug_assertions)]
-            {
-                let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
-                MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
+    fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
+        match &self.args {
+            AttrArgs::Delimited(args) if args.delim == MacDelimiter::Parenthesis => {
+                MetaItemKind::list_from_tokens(args.tokens.clone())
             }
-
-            Cell::new(index.reverse_bits())
-        }))
+            AttrArgs::Delimited(_) | AttrArgs::Eq(..) | AttrArgs::Empty => None,
+        }
     }
 
-    pub fn mk_attr_id(&self) -> AttrId {
-        let id = self.0.get();
+    fn value_str(&self) -> Option<Symbol> {
+        match &self.args {
+            AttrArgs::Eq(_, args) => args.value_str(),
+            AttrArgs::Delimited(_) | AttrArgs::Empty => None,
+        }
+    }
 
-        // Ensure the assigned attr_id does not overlap the bits
-        // representing the number of threads.
-        #[cfg(debug_assertions)]
-        assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
+    pub fn meta(&self, span: Span) -> Option<MetaItem> {
+        Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
+    }
 
-        self.0.set(id + 1);
-        AttrId::from_u32(id)
+    pub fn meta_kind(&self) -> Option<MetaItemKind> {
+        MetaItemKind::from_attr_args(&self.args)
     }
 }
 
-pub fn mk_attr(
-    g: &AttrIdGenerator,
-    style: AttrStyle,
-    path: Path,
-    args: AttrArgs,
-    span: Span,
-) -> Attribute {
-    mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
+impl AttrArgsEq {
+    fn value_str(&self) -> Option<Symbol> {
+        match self {
+            AttrArgsEq::Ast(expr) => match expr.kind {
+                ExprKind::Lit(token_lit) => {
+                    LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
+                }
+                _ => None,
+            },
+            AttrArgsEq::Hir(lit) => lit.kind.str(),
+        }
+    }
 }
 
-pub fn mk_attr_from_item(
-    g: &AttrIdGenerator,
-    item: AttrItem,
-    tokens: Option<LazyAttrTokenStream>,
-    style: AttrStyle,
-    span: Span,
-) -> Attribute {
-    Attribute {
-        kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
-        id: g.mk_attr_id(),
-        style,
-        span,
+impl MetaItem {
+    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
     }
-}
 
-pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
-    let path = Path::from_ident(Ident::new(name, span));
-    let args = AttrArgs::Empty;
-    mk_attr(g, style, path, args, span)
-}
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or_else(Ident::empty).name
+    }
 
-pub fn mk_attr_name_value_str(
-    g: &AttrIdGenerator,
-    style: AttrStyle,
-    name: Symbol,
-    val: Symbol,
-    span: Span,
-) -> Attribute {
-    let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
-    let expr = P(Expr {
-        id: DUMMY_NODE_ID,
-        kind: ExprKind::Lit(lit),
-        span,
-        attrs: AttrVec::new(),
-        tokens: None,
-    });
-    let path = Path::from_ident(Ident::new(name, span));
-    let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
-    mk_attr(g, style, path, args, span)
-}
+    pub fn has_name(&self, name: Symbol) -> bool {
+        self.path == name
+    }
 
-pub fn mk_attr_nested_word(
-    g: &AttrIdGenerator,
-    style: AttrStyle,
-    outer: Symbol,
-    inner: Symbol,
-    span: Span,
-) -> Attribute {
-    let inner_tokens = TokenStream::new(vec![TokenTree::Token(
-        Token::from_ast_ident(Ident::new(inner, span)),
-        Spacing::Alone,
-    )]);
-    let outer_ident = Ident::new(outer, span);
-    let path = Path::from_ident(outer_ident);
-    let attr_args = AttrArgs::Delimited(DelimArgs {
-        dspan: DelimSpan::from_single(span),
-        delim: MacDelimiter::Parenthesis,
-        tokens: inner_tokens,
-    });
-    mk_attr(g, style, path, attr_args, span)
-}
+    pub fn is_word(&self) -> bool {
+        matches!(self.kind, MetaItemKind::Word)
+    }
 
-pub fn mk_doc_comment(
-    g: &AttrIdGenerator,
-    comment_kind: CommentKind,
-    style: AttrStyle,
-    data: Symbol,
-    span: Span,
-) -> Attribute {
-    Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
-}
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        match &self.kind {
+            MetaItemKind::List(l) => Some(&**l),
+            _ => None,
+        }
+    }
 
-pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
-    items.iter().any(|item| item.has_name(name))
-}
+    /// ```text
+    /// Example:
+    ///     #[attribute(name = "value")]
+    ///                 ^^^^^^^^^^^^^^
+    /// ```
+    pub fn name_value_literal(&self) -> Option<&MetaItemLit> {
+        match &self.kind {
+            MetaItemKind::NameValue(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    /// This is used in case you want the value span instead of the whole attribute. Example:
+    ///
+    /// ```text
+    /// #[doc(alias = "foo")]
+    /// ```
+    ///
+    /// In here, it'll return a span for `"foo"`.
+    pub fn name_value_literal_span(&self) -> Option<Span> {
+        Some(self.name_value_literal()?.span)
+    }
+
+    pub fn value_str(&self) -> Option<Symbol> {
+        self.kind.value_str()
+    }
 
-impl MetaItem {
     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
     where
         I: Iterator<Item = TokenTree>,
@@ -564,6 +403,24 @@ impl MetaItemKind {
         }
     }
 
+    fn from_tokens(
+        tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
+    ) -> Option<MetaItemKind> {
+        match tokens.peek() {
+            Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
+                let inner_tokens = inner_tokens.clone();
+                tokens.next();
+                MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
+            }
+            Some(TokenTree::Delimited(..)) => None,
+            Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
+                tokens.next();
+                MetaItemKind::name_value_from_tokens(tokens)
+            }
+            _ => Some(MetaItemKind::Word),
+        }
+    }
+
     fn from_attr_args(args: &AttrArgs) -> Option<MetaItemKind> {
         match args {
             AttrArgs::Empty => Some(MetaItemKind::Word),
@@ -585,24 +442,6 @@ impl MetaItemKind {
             AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => Some(MetaItemKind::NameValue(lit.clone())),
         }
     }
-
-    fn from_tokens(
-        tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
-    ) -> Option<MetaItemKind> {
-        match tokens.peek() {
-            Some(TokenTree::Delimited(_, Delimiter::Parenthesis, inner_tokens)) => {
-                let inner_tokens = inner_tokens.clone();
-                tokens.next();
-                MetaItemKind::list_from_tokens(inner_tokens).map(MetaItemKind::List)
-            }
-            Some(TokenTree::Delimited(..)) => None,
-            Some(TokenTree::Token(Token { kind: token::Eq, .. }, _)) => {
-                tokens.next();
-                MetaItemKind::name_value_from_tokens(tokens)
-            }
-            _ => Some(MetaItemKind::Word),
-        }
-    }
 }
 
 impl NestedMetaItem {
@@ -613,6 +452,77 @@ impl NestedMetaItem {
         }
     }
 
+    /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+    pub fn ident(&self) -> Option<Ident> {
+        self.meta_item().and_then(|meta_item| meta_item.ident())
+    }
+
+    pub fn name_or_empty(&self) -> Symbol {
+        self.ident().unwrap_or_else(Ident::empty).name
+    }
+
+    /// Returns `true` if this list item is a MetaItem with a name of `name`.
+    pub fn has_name(&self, name: Symbol) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
+    }
+
+    /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
+    pub fn is_word(&self) -> bool {
+        self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+    }
+
+    /// Gets a list of inner meta items from a list `MetaItem` type.
+    pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
+        self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
+    }
+
+    /// Returns a name and single literal value tuple of the `MetaItem`.
+    pub fn name_value_literal(&self) -> Option<(Symbol, &MetaItemLit)> {
+        self.meta_item().and_then(|meta_item| {
+            meta_item.meta_item_list().and_then(|meta_item_list| {
+                if meta_item_list.len() == 1
+                    && let Some(ident) = meta_item.ident()
+                    && let Some(lit) = meta_item_list[0].lit()
+                {
+                    return Some((ident.name, lit));
+                }
+                None
+            })
+        })
+    }
+
+    /// See [`MetaItem::name_value_literal_span`].
+    pub fn name_value_literal_span(&self) -> Option<Span> {
+        self.meta_item()?.name_value_literal_span()
+    }
+
+    /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
+    /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
+    pub fn value_str(&self) -> Option<Symbol> {
+        self.meta_item().and_then(|meta_item| meta_item.value_str())
+    }
+
+    /// Returns the `MetaItemLit` if `self` is a `NestedMetaItem::Literal`s.
+    pub fn lit(&self) -> Option<&MetaItemLit> {
+        match self {
+            NestedMetaItem::Lit(lit) => Some(lit),
+            _ => None,
+        }
+    }
+
+    /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
+    pub fn meta_item(&self) -> Option<&MetaItem> {
+        match self {
+            NestedMetaItem::MetaItem(item) => Some(item),
+            _ => None,
+        }
+    }
+
+    /// Returns `true` if the variant is `MetaItem`.
+    pub fn is_meta_item(&self) -> bool {
+        self.meta_item().is_some()
+    }
+
     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
     where
         I: Iterator<Item = TokenTree>,
@@ -634,3 +544,89 @@ impl NestedMetaItem {
         MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
     }
 }
+
+pub fn mk_doc_comment(
+    g: &AttrIdGenerator,
+    comment_kind: CommentKind,
+    style: AttrStyle,
+    data: Symbol,
+    span: Span,
+) -> Attribute {
+    Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
+}
+
+pub fn mk_attr(
+    g: &AttrIdGenerator,
+    style: AttrStyle,
+    path: Path,
+    args: AttrArgs,
+    span: Span,
+) -> Attribute {
+    mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
+}
+
+pub fn mk_attr_from_item(
+    g: &AttrIdGenerator,
+    item: AttrItem,
+    tokens: Option<LazyAttrTokenStream>,
+    style: AttrStyle,
+    span: Span,
+) -> Attribute {
+    Attribute {
+        kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
+        id: g.mk_attr_id(),
+        style,
+        span,
+    }
+}
+
+pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
+    let path = Path::from_ident(Ident::new(name, span));
+    let args = AttrArgs::Empty;
+    mk_attr(g, style, path, args, span)
+}
+
+pub fn mk_attr_nested_word(
+    g: &AttrIdGenerator,
+    style: AttrStyle,
+    outer: Symbol,
+    inner: Symbol,
+    span: Span,
+) -> Attribute {
+    let inner_tokens = TokenStream::new(vec![TokenTree::Token(
+        Token::from_ast_ident(Ident::new(inner, span)),
+        Spacing::Alone,
+    )]);
+    let outer_ident = Ident::new(outer, span);
+    let path = Path::from_ident(outer_ident);
+    let attr_args = AttrArgs::Delimited(DelimArgs {
+        dspan: DelimSpan::from_single(span),
+        delim: MacDelimiter::Parenthesis,
+        tokens: inner_tokens,
+    });
+    mk_attr(g, style, path, attr_args, span)
+}
+
+pub fn mk_attr_name_value_str(
+    g: &AttrIdGenerator,
+    style: AttrStyle,
+    name: Symbol,
+    val: Symbol,
+    span: Span,
+) -> Attribute {
+    let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
+    let expr = P(Expr {
+        id: DUMMY_NODE_ID,
+        kind: ExprKind::Lit(lit),
+        span,
+        attrs: AttrVec::new(),
+        tokens: None,
+    });
+    let path = Path::from_ident(Ident::new(name, span));
+    let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
+    mk_attr(g, style, path, args, span)
+}
+
+pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
+    items.iter().any(|item| item.has_name(name))
+}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 37967bfdff5..1067fcebcf3 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -23,7 +23,7 @@ use rustc_codegen_ssa::{traits::CodegenBackend, CodegenErrors, CodegenResults};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
-use rustc_errors::{ErrorGuaranteed, PResult};
+use rustc_errors::{ErrorGuaranteed, PResult, TerminalUrl};
 use rustc_feature::find_gated_cfg;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
@@ -1191,6 +1191,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         None,
         false,
         false,
+        TerminalUrl::No,
     ));
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
 
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 5f460b26488..4f2cc8b0351 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -18,7 +18,7 @@ use crate::translation::{to_fluent_args, Translate};
 use crate::{
     diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage,
     FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
-    SubstitutionHighlight, SuggestionStyle,
+    SubstitutionHighlight, SuggestionStyle, TerminalUrl,
 };
 use rustc_lint_defs::pluralize;
 
@@ -66,6 +66,7 @@ impl HumanReadableErrorType {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> EmitterWriter {
         let (short, color_config) = self.unzip();
         let color = color_config.suggests_using_colors();
@@ -80,6 +81,7 @@ impl HumanReadableErrorType {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         )
     }
 }
@@ -652,6 +654,7 @@ pub struct EmitterWriter {
 
     macro_backtrace: bool,
     track_diagnostics: bool,
+    terminal_url: TerminalUrl,
 }
 
 #[derive(Debug)]
@@ -672,6 +675,7 @@ impl EmitterWriter {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> EmitterWriter {
         let dst = Destination::from_stderr(color_config);
         EmitterWriter {
@@ -685,6 +689,7 @@ impl EmitterWriter {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         }
     }
 
@@ -699,6 +704,7 @@ impl EmitterWriter {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> EmitterWriter {
         EmitterWriter {
             dst: Raw(dst, colored),
@@ -711,6 +717,7 @@ impl EmitterWriter {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         }
     }
 
@@ -1378,7 +1385,13 @@ impl EmitterWriter {
             // only render error codes, not lint codes
             if let Some(DiagnosticId::Error(ref code)) = *code {
                 buffer.append(0, "[", Style::Level(*level));
-                buffer.append(0, code, Style::Level(*level));
+                let code = if let TerminalUrl::Yes = self.terminal_url {
+                    let path = "https://doc.rust-lang.org/error_codes";
+                    format!("\x1b]8;;{path}/{code}.html\x07{code}\x1b]8;;\x07")
+                } else {
+                    code.clone()
+                };
+                buffer.append(0, &code, Style::Level(*level));
                 buffer.append(0, "]", Style::Level(*level));
                 label_width += 2 + code.len();
             }
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index dc38b8725ad..e475fc725c3 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -17,6 +17,7 @@ use crate::translation::{to_fluent_args, Translate};
 use crate::DiagnosticId;
 use crate::{
     CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic,
+    TerminalUrl,
 };
 use rustc_lint_defs::Applicability;
 
@@ -47,6 +48,7 @@ pub struct JsonEmitter {
     diagnostic_width: Option<usize>,
     macro_backtrace: bool,
     track_diagnostics: bool,
+    terminal_url: TerminalUrl,
 }
 
 impl JsonEmitter {
@@ -60,6 +62,7 @@ impl JsonEmitter {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> JsonEmitter {
         JsonEmitter {
             dst: Box::new(io::BufWriter::new(io::stderr())),
@@ -73,6 +76,7 @@ impl JsonEmitter {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         }
     }
 
@@ -84,6 +88,7 @@ impl JsonEmitter {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
         JsonEmitter::stderr(
@@ -96,6 +101,7 @@ impl JsonEmitter {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         )
     }
 
@@ -110,6 +116,7 @@ impl JsonEmitter {
         diagnostic_width: Option<usize>,
         macro_backtrace: bool,
         track_diagnostics: bool,
+        terminal_url: TerminalUrl,
     ) -> JsonEmitter {
         JsonEmitter {
             dst,
@@ -123,6 +130,7 @@ impl JsonEmitter {
             diagnostic_width,
             macro_backtrace,
             track_diagnostics,
+            terminal_url,
         }
     }
 
@@ -360,6 +368,7 @@ impl Diagnostic {
                 je.diagnostic_width,
                 je.macro_backtrace,
                 je.track_diagnostics,
+                je.terminal_url,
             )
             .ui_testing(je.ui_testing)
             .emit_diagnostic(diag);
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index f131468971b..f161532d3b7 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -4,7 +4,7 @@ use crate::json::JsonEmitter;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
 
 use crate::emitter::{ColorConfig, HumanReadableErrorType};
-use crate::Handler;
+use crate::{Handler, TerminalUrl};
 use rustc_span::{BytePos, Span};
 
 use std::str;
@@ -60,6 +60,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
             None,
             false,
             false,
+            TerminalUrl::No,
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index ec04e865d53..83b733d4c06 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -573,6 +573,7 @@ impl Handler {
             None,
             flags.macro_backtrace,
             flags.track_diagnostics,
+            TerminalUrl::No,
         ));
         Self::with_emitter_and_flags(emitter, flags)
     }
@@ -1838,6 +1839,13 @@ pub fn add_elided_lifetime_in_path_suggestion(
     );
 }
 
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum TerminalUrl {
+    No,
+    Yes,
+    Auto,
+}
+
 /// Useful type to use with `Result<>` indicate that an error has already
 /// been reported to the user, so no need to continue checking.
 #[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq, PartialOrd, Ord)]
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 8f3bea29ffd..f80141403bf 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -8,7 +8,7 @@ use rustc_span::{BytePos, Span};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Handler, MultiSpan, PResult};
+use rustc_errors::{Handler, MultiSpan, PResult, TerminalUrl};
 
 use std::io;
 use std::io::prelude::*;
@@ -152,6 +152,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             None,
             false,
             false,
+            TerminalUrl::No,
         );
         let handler = Handler::with_emitter(true, None, Box::new(emitter));
         #[allow(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c975a52e3f3..81f7f6d72ae 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,7 +4,7 @@ use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
-use rustc_errors::LanguageIdentifier;
+use rustc_errors::{LanguageIdentifier, TerminalUrl};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{
     RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
@@ -402,6 +402,8 @@ mod desc {
     pub const parse_code_model: &str = "one of supported code models (`rustc --print code-models`)";
     pub const parse_tls_model: &str = "one of supported TLS models (`rustc --print tls-models`)";
     pub const parse_target_feature: &str = parse_string;
+    pub const parse_terminal_url: &str =
+        "either a boolean (`yes`, `no`, `on`, `off`, etc), or `auto`";
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
@@ -1044,6 +1046,16 @@ mod parse {
         true
     }
 
+    pub(crate) fn parse_terminal_url(slot: &mut TerminalUrl, v: Option<&str>) -> bool {
+        *slot = match v {
+            Some("on" | "" | "yes" | "y") | None => TerminalUrl::Yes,
+            Some("off" | "no" | "n") => TerminalUrl::No,
+            Some("auto") => TerminalUrl::Auto,
+            _ => return false,
+        };
+        true
+    }
+
     pub(crate) fn parse_symbol_mangling_version(
         slot: &mut Option<SymbolManglingVersion>,
         v: Option<&str>,
@@ -1675,6 +1687,8 @@ options! {
         "show extended diagnostic help (default: no)"),
     temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "the directory the intermediate files are written to"),
+    terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED],
+        "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"),
     #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index be1ff8559cf..e608b9fe0b3 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -24,6 +24,7 @@ use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
     ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
+    TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -1273,6 +1274,19 @@ fn default_emitter(
 ) -> Box<dyn Emitter + sync::Send> {
     let macro_backtrace = sopts.unstable_opts.macro_backtrace;
     let track_diagnostics = sopts.unstable_opts.track_diagnostics;
+    let terminal_url = match sopts.unstable_opts.terminal_urls {
+        TerminalUrl::Auto => {
+            match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
+                (Ok("truecolor"), Ok("xterm-256color"))
+                    if sopts.unstable_features.is_nightly_build() =>
+                {
+                    TerminalUrl::Yes
+                }
+                _ => TerminalUrl::No,
+            }
+        }
+        t => t,
+    };
     match sopts.error_format {
         config::ErrorOutputType::HumanReadable(kind) => {
             let (short, color_config) = kind.unzip();
@@ -1297,6 +1311,7 @@ fn default_emitter(
                     sopts.diagnostic_width,
                     macro_backtrace,
                     track_diagnostics,
+                    terminal_url,
                 );
                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
             }
@@ -1312,6 +1327,7 @@ fn default_emitter(
                 sopts.diagnostic_width,
                 macro_backtrace,
                 track_diagnostics,
+                terminal_url,
             )
             .ui_testing(sopts.unstable_opts.ui_testing),
         ),
@@ -1628,6 +1644,7 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
                 None,
                 false,
                 false,
+                TerminalUrl::No,
             ))
         }
         config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
@@ -1638,6 +1655,7 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
             None,
             false,
             false,
+            TerminalUrl::No,
         )),
     };
     rustc_errors::Handler::with_emitter(true, None, emitter)
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index d48c4f7e5a8..c600298c51a 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -110,11 +110,16 @@ impl Span {
                 // Inline format with parent.
                 let len_or_tag = len_or_tag | PARENT_MASK;
                 let parent2 = parent.local_def_index.as_u32();
-                if ctxt2 == SyntaxContext::root().as_u32() && parent2 <= MAX_CTXT {
+                if ctxt2 == SyntaxContext::root().as_u32()
+                    && parent2 <= MAX_CTXT
+                    && len_or_tag < LEN_TAG
+                {
+                    debug_assert_ne!(len_or_tag, LEN_TAG);
                     return Span { base_or_index: base, len_or_tag, ctxt_or_tag: parent2 as u16 };
                 }
             } else {
                 // Inline format with ctxt.
+                debug_assert_ne!(len_or_tag, LEN_TAG);
                 return Span {
                     base_or_index: base,
                     len_or_tag: len as u16,
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 2aeb255c164..13728919878 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -470,14 +470,11 @@ fn layout_of_uncached<'tcx>(
             return Err(LayoutError::Unknown(ty));
         }
 
-        ty::Placeholder(..)
-        | ty::GeneratorWitness(..)
-        | ty::GeneratorWitnessMIR(..)
-        | ty::Infer(_) => {
+        ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => {
             bug!("Layout::compute: unexpected type `{}`", ty)
         }
 
-        ty::Bound(..) | ty::Param(_) | ty::Error(_) => {
+        ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => {
             return Err(LayoutError::Unknown(ty));
         }
     })
diff --git a/library/core/src/array/drain.rs b/library/core/src/array/drain.rs
new file mode 100644
index 00000000000..5fadf907b62
--- /dev/null
+++ b/library/core/src/array/drain.rs
@@ -0,0 +1,76 @@
+use crate::iter::{TrustedLen, UncheckedIterator};
+use crate::mem::ManuallyDrop;
+use crate::ptr::drop_in_place;
+use crate::slice;
+
+/// A situationally-optimized version of `array.into_iter().for_each(func)`.
+///
+/// [`crate::array::IntoIter`]s are great when you need an owned iterator, but
+/// storing the entire array *inside* the iterator like that can sometimes
+/// pessimize code.  Notable, it can be more bytes than you really want to move
+/// around, and because the array accesses index into it SRoA has a harder time
+/// optimizing away the type than it does iterators that just hold a couple pointers.
+///
+/// Thus this function exists, which gives a way to get *moved* access to the
+/// elements of an array using a small iterator -- no bigger than a slice iterator.
+///
+/// The function-taking-a-closure structure makes it safe, as it keeps callers
+/// from looking at already-dropped elements.
+pub(crate) fn drain_array_with<T, R, const N: usize>(
+    array: [T; N],
+    func: impl for<'a> FnOnce(Drain<'a, T>) -> R,
+) -> R {
+    let mut array = ManuallyDrop::new(array);
+    // SAFETY: Now that the local won't drop it, it's ok to construct the `Drain` which will.
+    let drain = Drain(array.iter_mut());
+    func(drain)
+}
+
+/// See [`drain_array_with`] -- this is `pub(crate)` only so it's allowed to be
+/// mentioned in the signature of that method.  (Otherwise it hits `E0446`.)
+// INVARIANT: It's ok to drop the remainder of the inner iterator.
+pub(crate) struct Drain<'a, T>(slice::IterMut<'a, T>);
+
+impl<T> Drop for Drain<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: By the type invariant, we're allowed to drop all these.
+        unsafe { drop_in_place(self.0.as_mut_slice()) }
+    }
+}
+
+impl<T> Iterator for Drain<'_, T> {
+    type Item = T;
+
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        let p: *const T = self.0.next()?;
+        // SAFETY: The iterator was already advanced, so we won't drop this later.
+        Some(unsafe { p.read() })
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let n = self.len();
+        (n, Some(n))
+    }
+}
+
+impl<T> ExactSizeIterator for Drain<'_, T> {
+    #[inline]
+    fn len(&self) -> usize {
+        self.0.len()
+    }
+}
+
+// SAFETY: This is a 1:1 wrapper for a slice iterator, which is also `TrustedLen`.
+unsafe impl<T> TrustedLen for Drain<'_, T> {}
+
+impl<T> UncheckedIterator for Drain<'_, T> {
+    unsafe fn next_unchecked(&mut self) -> T {
+        // SAFETY: `Drain` is 1:1 with the inner iterator, so if the caller promised
+        // that there's an element left, the inner iterator has one too.
+        let p: *const T = unsafe { self.0.next_unchecked() };
+        // SAFETY: The iterator was already advanced, so we won't drop this later.
+        unsafe { p.read() }
+    }
+}
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 5decd7d5a65..1643842d607 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -10,16 +10,19 @@ use crate::convert::{Infallible, TryFrom};
 use crate::error::Error;
 use crate::fmt;
 use crate::hash::{self, Hash};
-use crate::iter::TrustedLen;
+use crate::iter::UncheckedIterator;
 use crate::mem::{self, MaybeUninit};
 use crate::ops::{
     ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
 };
 use crate::slice::{Iter, IterMut};
 
+mod drain;
 mod equality;
 mod iter;
 
+pub(crate) use drain::drain_array_with;
+
 #[stable(feature = "array_value_iter", since = "1.51.0")]
 pub use iter::IntoIter;
 
@@ -52,16 +55,11 @@ pub use iter::IntoIter;
 /// ```
 #[inline]
 #[stable(feature = "array_from_fn", since = "1.63.0")]
-pub fn from_fn<T, const N: usize, F>(mut cb: F) -> [T; N]
+pub fn from_fn<T, const N: usize, F>(cb: F) -> [T; N]
 where
     F: FnMut(usize) -> T,
 {
-    let mut idx = 0;
-    [(); N].map(|_| {
-        let res = cb(idx);
-        idx += 1;
-        res
-    })
+    try_from_fn(NeverShortCircuit::wrap_mut_1(cb)).0
 }
 
 /// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
@@ -101,9 +99,14 @@ where
     R: Try,
     R::Residual: Residual<[R::Output; N]>,
 {
-    // SAFETY: we know for certain that this iterator will yield exactly `N`
-    // items.
-    unsafe { try_collect_into_array_unchecked(&mut (0..N).map(cb)) }
+    let mut array = MaybeUninit::uninit_array::<N>();
+    match try_from_fn_erased(&mut array, cb) {
+        ControlFlow::Break(r) => FromResidual::from_residual(r),
+        ControlFlow::Continue(()) => {
+            // SAFETY: All elements of the array were populated.
+            try { unsafe { MaybeUninit::array_assume_init(array) } }
+        }
+    }
 }
 
 /// Converts a reference to `T` into a reference to an array of length 1 (without copying).
@@ -414,9 +417,7 @@ trait SpecArrayClone: Clone {
 impl<T: Clone> SpecArrayClone for T {
     #[inline]
     default fn clone<const N: usize>(array: &[T; N]) -> [T; N] {
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { collect_into_array_unchecked(&mut array.iter().cloned()) }
+        from_trusted_iterator(array.iter().cloned())
     }
 }
 
@@ -500,9 +501,7 @@ impl<T, const N: usize> [T; N] {
     where
         F: FnMut(T) -> U,
     {
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
+        self.try_map(NeverShortCircuit::wrap_mut_1(f)).0
     }
 
     /// A fallible function `f` applied to each element on array `self` in order to
@@ -539,9 +538,7 @@ impl<T, const N: usize> [T; N] {
         R: Try,
         R::Residual: Residual<[R::Output; N]>,
     {
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { try_collect_into_array_unchecked(&mut IntoIterator::into_iter(self).map(f)) }
+        drain_array_with(self, |iter| try_from_trusted_iterator(iter.map(f)))
     }
 
     /// 'Zips up' two arrays into a single array of pairs.
@@ -562,11 +559,9 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_zip", issue = "80094")]
     pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
-        let mut iter = IntoIterator::into_iter(self).zip(rhs);
-
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { collect_into_array_unchecked(&mut iter) }
+        drain_array_with(self, |lhs| {
+            drain_array_with(rhs, |rhs| from_trusted_iterator(crate::iter::zip(lhs, rhs)))
+        })
     }
 
     /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
@@ -613,9 +608,7 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_methods", issue = "76118")]
     pub fn each_ref(&self) -> [&T; N] {
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { collect_into_array_unchecked(&mut self.iter()) }
+        from_trusted_iterator(self.iter())
     }
 
     /// Borrows each element mutably and returns an array of mutable references
@@ -635,9 +628,7 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_methods", issue = "76118")]
     pub fn each_mut(&mut self) -> [&mut T; N] {
-        // SAFETY: we know for certain that this iterator will yield exactly `N`
-        // items.
-        unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
+        from_trusted_iterator(self.iter_mut())
     }
 
     /// Divides one array reference into two at an index.
@@ -797,105 +788,71 @@ impl<T, const N: usize> [T; N] {
     }
 }
 
-/// Pulls `N` items from `iter` and returns them as an array. If the iterator
-/// yields fewer than `N` items, this function exhibits undefined behavior.
-///
-/// See [`try_collect_into_array`] for more information.
+/// Populate an array from the first `N` elements of `iter`
 ///
+/// # Panics
 ///
-/// # Safety
+/// If the iterator doesn't actually have enough items.
 ///
-/// It is up to the caller to guarantee that `iter` yields at least `N` items.
-/// Violating this condition causes undefined behavior.
-unsafe fn try_collect_into_array_unchecked<I, T, R, const N: usize>(iter: &mut I) -> R::TryType
-where
-    // Note: `TrustedLen` here is somewhat of an experiment. This is just an
-    // internal function, so feel free to remove if this bound turns out to be a
-    // bad idea. In that case, remember to also remove the lower bound
-    // `debug_assert!` below!
-    I: Iterator + TrustedLen,
-    I::Item: Try<Output = T, Residual = R>,
-    R: Residual<[T; N]>,
-{
-    debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
-    debug_assert!(N <= iter.size_hint().0);
-
-    // SAFETY: covered by the function contract.
-    unsafe { try_collect_into_array(iter).unwrap_unchecked() }
+/// By depending on `TrustedLen`, however, we can do that check up-front (where
+/// it easily optimizes away) so it doesn't impact the loop that fills the array.
+#[inline]
+fn from_trusted_iterator<T, const N: usize>(iter: impl UncheckedIterator<Item = T>) -> [T; N] {
+    try_from_trusted_iterator(iter.map(NeverShortCircuit)).0
 }
 
-// Infallible version of `try_collect_into_array_unchecked`.
-unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
+#[inline]
+fn try_from_trusted_iterator<T, R, const N: usize>(
+    iter: impl UncheckedIterator<Item = R>,
+) -> ChangeOutputType<R, [T; N]>
 where
-    I: Iterator + TrustedLen,
+    R: Try<Output = T>,
+    R::Residual: Residual<[T; N]>,
 {
-    let mut map = iter.map(NeverShortCircuit);
-
-    // SAFETY: The same safety considerations w.r.t. the iterator length
-    // apply for `try_collect_into_array_unchecked` as for
-    // `collect_into_array_unchecked`
-    match unsafe { try_collect_into_array_unchecked(&mut map) } {
-        NeverShortCircuit(array) => array,
+    assert!(iter.size_hint().0 >= N);
+    fn next<T>(mut iter: impl UncheckedIterator<Item = T>) -> impl FnMut(usize) -> T {
+        move |_| {
+            // SAFETY: We know that `from_fn` will call this at most N times,
+            // and we checked to ensure that we have at least that many items.
+            unsafe { iter.next_unchecked() }
+        }
     }
+
+    try_from_fn(next(iter))
 }
 
-/// Pulls `N` items from `iter` and returns them as an array. If the iterator
-/// yields fewer than `N` items, `Err` is returned containing an iterator over
-/// the already yielded items.
+/// Version of [`try_from_fn`] using a passed-in slice in order to avoid
+/// needing to monomorphize for every array length.
 ///
-/// Since the iterator is passed as a mutable reference and this function calls
-/// `next` at most `N` times, the iterator can still be used afterwards to
-/// retrieve the remaining items.
+/// This takes a generator rather than an iterator so that *at the type level*
+/// it never needs to worry about running out of items.  When combined with
+/// an infallible `Try` type, that means the loop canonicalizes easily, allowing
+/// it to optimize well.
 ///
-/// If `iter.next()` panicks, all items already yielded by the iterator are
-/// dropped.
+/// It would be *possible* to unify this and [`iter_next_chunk_erased`] into one
+/// function that does the union of both things, but last time it was that way
+/// it resulted in poor codegen from the "are there enough source items?" checks
+/// not optimizing away.  So if you give it a shot, make sure to watch what
+/// happens in the codegen tests.
 #[inline]
-fn try_collect_into_array<I, T, R, const N: usize>(
-    iter: &mut I,
-) -> Result<R::TryType, IntoIter<T, N>>
+fn try_from_fn_erased<T, R>(
+    buffer: &mut [MaybeUninit<T>],
+    mut generator: impl FnMut(usize) -> R,
+) -> ControlFlow<R::Residual>
 where
-    I: Iterator,
-    I::Item: Try<Output = T, Residual = R>,
-    R: Residual<[T; N]>,
+    R: Try<Output = T>,
 {
-    if N == 0 {
-        // SAFETY: An empty array is always inhabited and has no validity invariants.
-        return Ok(Try::from_output(unsafe { mem::zeroed() }));
-    }
+    let mut guard = Guard { array_mut: buffer, initialized: 0 };
 
-    let mut array = MaybeUninit::uninit_array::<N>();
-    let mut guard = Guard { array_mut: &mut array, initialized: 0 };
-
-    for _ in 0..N {
-        match iter.next() {
-            Some(item_rslt) => {
-                let item = match item_rslt.branch() {
-                    ControlFlow::Break(r) => {
-                        return Ok(FromResidual::from_residual(r));
-                    }
-                    ControlFlow::Continue(elem) => elem,
-                };
-
-                // SAFETY: `guard.initialized` starts at 0, which means push can be called
-                // at most N times, which this loop does.
-                unsafe {
-                    guard.push_unchecked(item);
-                }
-            }
-            None => {
-                let alive = 0..guard.initialized;
-                mem::forget(guard);
-                // SAFETY: `array` was initialized with exactly `initialized`
-                // number of elements.
-                return Err(unsafe { IntoIter::new_unchecked(array, alive) });
-            }
-        }
+    while guard.initialized < guard.array_mut.len() {
+        let item = generator(guard.initialized).branch()?;
+
+        // SAFETY: The loop condition ensures we have space to push the item
+        unsafe { guard.push_unchecked(item) };
     }
 
     mem::forget(guard);
-    // SAFETY: All elements of the array were populated in the loop above.
-    let output = unsafe { array.transpose().assume_init() };
-    Ok(Try::from_output(output))
+    ControlFlow::Continue(())
 }
 
 /// Panic guard for incremental initialization of arrays.
@@ -909,14 +866,14 @@ where
 ///
 /// To minimize indirection fields are still pub but callers should at least use
 /// `push_unchecked` to signal that something unsafe is going on.
-pub(crate) struct Guard<'a, T, const N: usize> {
+struct Guard<'a, T> {
     /// The array to be initialized.
-    pub array_mut: &'a mut [MaybeUninit<T>; N],
+    pub array_mut: &'a mut [MaybeUninit<T>],
     /// The number of items that have been initialized so far.
     pub initialized: usize,
 }
 
-impl<T, const N: usize> Guard<'_, T, N> {
+impl<T> Guard<'_, T> {
     /// Adds an item to the array and updates the initialized item counter.
     ///
     /// # Safety
@@ -934,28 +891,73 @@ impl<T, const N: usize> Guard<'_, T, N> {
     }
 }
 
-impl<T, const N: usize> Drop for Guard<'_, T, N> {
+impl<T> Drop for Guard<'_, T> {
     fn drop(&mut self) {
-        debug_assert!(self.initialized <= N);
+        debug_assert!(self.initialized <= self.array_mut.len());
 
         // SAFETY: this slice will contain only initialized objects.
         unsafe {
             crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
-                &mut self.array_mut.get_unchecked_mut(..self.initialized),
+                self.array_mut.get_unchecked_mut(..self.initialized),
             ));
         }
     }
 }
 
-/// Returns the next chunk of `N` items from the iterator or errors with an
-/// iterator over the remainder. Used for `Iterator::next_chunk`.
+/// Pulls `N` items from `iter` and returns them as an array. If the iterator
+/// yields fewer than `N` items, `Err` is returned containing an iterator over
+/// the already yielded items.
+///
+/// Since the iterator is passed as a mutable reference and this function calls
+/// `next` at most `N` times, the iterator can still be used afterwards to
+/// retrieve the remaining items.
+///
+/// If `iter.next()` panicks, all items already yielded by the iterator are
+/// dropped.
+///
+/// Used for [`Iterator::next_chunk`].
 #[inline]
-pub(crate) fn iter_next_chunk<I, const N: usize>(
-    iter: &mut I,
-) -> Result<[I::Item; N], IntoIter<I::Item, N>>
-where
-    I: Iterator,
-{
-    let mut map = iter.map(NeverShortCircuit);
-    try_collect_into_array(&mut map).map(|NeverShortCircuit(arr)| arr)
+pub(crate) fn iter_next_chunk<T, const N: usize>(
+    iter: &mut impl Iterator<Item = T>,
+) -> Result<[T; N], IntoIter<T, N>> {
+    let mut array = MaybeUninit::uninit_array::<N>();
+    let r = iter_next_chunk_erased(&mut array, iter);
+    match r {
+        Ok(()) => {
+            // SAFETY: All elements of `array` were populated.
+            Ok(unsafe { MaybeUninit::array_assume_init(array) })
+        }
+        Err(initialized) => {
+            // SAFETY: Only the first `initialized` elements were populated
+            Err(unsafe { IntoIter::new_unchecked(array, 0..initialized) })
+        }
+    }
+}
+
+/// Version of [`iter_next_chunk`] using a passed-in slice in order to avoid
+/// needing to monomorphize for every array length.
+///
+/// Unfortunately this loop has two exit conditions, the buffer filling up
+/// or the iterator running out of items, making it tend to optimize poorly.
+#[inline]
+fn iter_next_chunk_erased<T>(
+    buffer: &mut [MaybeUninit<T>],
+    iter: &mut impl Iterator<Item = T>,
+) -> Result<(), usize> {
+    let mut guard = Guard { array_mut: buffer, initialized: 0 };
+    while guard.initialized < guard.array_mut.len() {
+        let Some(item) = iter.next() else {
+            // Unlike `try_from_fn_erased`, we want to keep the partial results,
+            // so we need to defuse the guard instead of using `?`.
+            let initialized = guard.initialized;
+            mem::forget(guard);
+            return Err(initialized)
+        };
+
+        // SAFETY: The loop condition ensures we have space to push the item
+        unsafe { guard.push_unchecked(item) };
+    }
+
+    mem::forget(guard);
+    Ok(())
 }
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
index af786609757..13719c727e9 100644
--- a/library/core/src/iter/adapters/array_chunks.rs
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -1,6 +1,5 @@
 use crate::array;
 use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
-use crate::mem::{self, MaybeUninit};
 use crate::ops::{ControlFlow, NeverShortCircuit, Try};
 
 /// An iterator over `N` elements of the iterator at a time.
@@ -212,19 +211,14 @@ where
         let mut i = 0;
         // Use a while loop because (0..len).step_by(N) doesn't optimize well.
         while inner_len - i >= N {
-            let mut chunk = MaybeUninit::uninit_array();
-            let mut guard = array::Guard { array_mut: &mut chunk, initialized: 0 };
-            while guard.initialized < N {
+            let chunk = crate::array::from_fn(|local| {
                 // SAFETY: The method consumes the iterator and the loop condition ensures that
                 // all accesses are in bounds and only happen once.
                 unsafe {
-                    let idx = i + guard.initialized;
-                    guard.push_unchecked(self.iter.__iterator_get_unchecked(idx));
+                    let idx = i + local;
+                    self.iter.__iterator_get_unchecked(idx)
                 }
-            }
-            mem::forget(guard);
-            // SAFETY: The loop above initialized all elements
-            let chunk = unsafe { MaybeUninit::array_assume_init(chunk) };
+            });
             accum = f(accum, chunk);
             i += N;
         }
diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs
index aba24a79dcf..914ff86c1a9 100644
--- a/library/core/src/iter/adapters/cloned.rs
+++ b/library/core/src/iter/adapters/cloned.rs
@@ -1,7 +1,7 @@
 use crate::iter::adapters::{
     zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
-use crate::iter::{FusedIterator, TrustedLen};
+use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator};
 use crate::ops::Try;
 
 /// An iterator that clones the elements of an underlying iterator.
@@ -140,3 +140,16 @@ where
     T: Clone,
 {
 }
+
+impl<'a, I, T: 'a> UncheckedIterator for Cloned<I>
+where
+    I: UncheckedIterator<Item = &'a T>,
+    T: Clone,
+{
+    unsafe fn next_unchecked(&mut self) -> T {
+        // SAFETY: `Cloned` is 1:1 with the inner iterator, so if the caller promised
+        // that there's an element left, the inner iterator has one too.
+        let item = unsafe { self.it.next_unchecked() };
+        item.clone()
+    }
+}
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index 9e25dbe462c..31d02a4da6e 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -2,7 +2,7 @@ use crate::fmt;
 use crate::iter::adapters::{
     zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
 };
-use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
+use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator};
 use crate::ops::Try;
 
 /// An iterator that maps the values of `iter` with `f`.
@@ -187,6 +187,19 @@ where
 {
 }
 
+impl<B, I, F> UncheckedIterator for Map<I, F>
+where
+    I: UncheckedIterator,
+    F: FnMut(I::Item) -> B,
+{
+    unsafe fn next_unchecked(&mut self) -> B {
+        // SAFETY: `Map` is 1:1 with the inner iterator, so if the caller promised
+        // that there's an element left, the inner iterator has one too.
+        let item = unsafe { self.iter.next_unchecked() };
+        (self.f)(item)
+    }
+}
+
 #[doc(hidden)]
 #[unstable(feature = "trusted_random_access", issue = "none")]
 unsafe impl<I, F> TrustedRandomAccess for Map<I, F> where I: TrustedRandomAccess {}
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 8153c8cfef1..b6b0c90cb7d 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -1,7 +1,7 @@
 use crate::cmp;
 use crate::fmt::{self, Debug};
 use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator};
-use crate::iter::{InPlaceIterable, SourceIter, TrustedLen};
+use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, UncheckedIterator};
 
 /// An iterator that iterates two other iterators simultaneously.
 ///
@@ -417,6 +417,13 @@ where
 {
 }
 
+impl<A, B> UncheckedIterator for Zip<A, B>
+where
+    A: UncheckedIterator,
+    B: UncheckedIterator,
+{
+}
+
 // Arbitrarily selects the left side of the zip iteration as extractable "source"
 // it would require negative trait bounds to be able to try both
 #[unstable(issue = "none", feature = "inplace_iteration")]
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 00f57fbcc61..156b925de77 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -450,6 +450,7 @@ pub use self::adapters::{
 pub use self::adapters::{Intersperse, IntersperseWith};
 
 pub(crate) use self::adapters::try_process;
+pub(crate) use self::traits::UncheckedIterator;
 
 mod adapters;
 mod range;
diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs
index ed0fb634dbf..41ea29e6a84 100644
--- a/library/core/src/iter/traits/mod.rs
+++ b/library/core/src/iter/traits/mod.rs
@@ -4,6 +4,7 @@ mod double_ended;
 mod exact_size;
 mod iterator;
 mod marker;
+mod unchecked_iterator;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::{
@@ -19,3 +20,5 @@ pub use self::{
 pub use self::marker::InPlaceIterable;
 #[unstable(feature = "trusted_step", issue = "85731")]
 pub use self::marker::TrustedStep;
+
+pub(crate) use self::unchecked_iterator::UncheckedIterator;
diff --git a/library/core/src/iter/traits/unchecked_iterator.rs b/library/core/src/iter/traits/unchecked_iterator.rs
new file mode 100644
index 00000000000..ae4bfcad4e6
--- /dev/null
+++ b/library/core/src/iter/traits/unchecked_iterator.rs
@@ -0,0 +1,36 @@
+use crate::iter::TrustedLen;
+
+/// [`TrustedLen`] cannot have methods, so this allows augmenting it.
+///
+/// It currently requires `TrustedLen` because it's unclear whether it's
+/// reasonably possible to depend on the `size_hint` of anything else.
+pub(crate) trait UncheckedIterator: TrustedLen {
+    /// Gets the next item from a non-empty iterator.
+    ///
+    /// Because there's always a value to return, that means it can return
+    /// the `Item` type directly, without wrapping it in an `Option`.
+    ///
+    /// # Safety
+    ///
+    /// This can only be called if `size_hint().0 != 0`, guaranteeing that
+    /// there's at least one item available.
+    ///
+    /// Otherwise (aka when `size_hint().1 == Some(0)`), this is UB.
+    ///
+    /// # Note to Implementers
+    ///
+    /// This has a default implementation using [`Option::unwrap_unchecked`].
+    /// That's probably sufficient if your `next` *always* returns `Some`,
+    /// such as for infinite iterators.  In more complicated situations, however,
+    /// sometimes there can still be `insertvalue`/`assume`/`extractvalue`
+    /// instructions remaining in the IR from the `Option` handling, at which
+    /// point you might want to implement this manually instead.
+    #[unstable(feature = "trusted_len_next_unchecked", issue = "37572")]
+    #[inline]
+    unsafe fn next_unchecked(&mut self) -> Self::Item {
+        let opt = self.next();
+        // SAFETY: The caller promised that we're not empty, and
+        // `Self: TrustedLen` so we can actually trust the `size_hint`.
+        unsafe { opt.unwrap_unchecked() }
+    }
+}
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 9108fc63045..86aa1e4fd20 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -379,6 +379,15 @@ pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::
 pub(crate) struct NeverShortCircuit<T>(pub T);
 
 impl<T> NeverShortCircuit<T> {
+    /// Wraps a unary function to produce one that wraps the output into a `NeverShortCircuit`.
+    ///
+    /// This is useful for implementing infallible functions in terms of the `try_` ones,
+    /// without accidentally capturing extra generic parameters in a closure.
+    #[inline]
+    pub fn wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T> {
+        move |a| NeverShortCircuit(f(a))
+    }
+
     #[inline]
     pub fn wrap_mut_2<A, B>(
         mut f: impl ~const FnMut(A, B) -> T,
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 90ab43d1289..c4317799bcc 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -7,7 +7,9 @@ use crate::cmp;
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::intrinsics::assume;
-use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
+use crate::iter::{
+    FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, UncheckedIterator,
+};
 use crate::marker::{PhantomData, Send, Sized, Sync};
 use crate::mem::{self, SizedTypeProperties};
 use crate::num::NonZeroUsize;
diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs
index 0fd57b197aa..89b92a7d597 100644
--- a/library/core/src/slice/iter/macros.rs
+++ b/library/core/src/slice/iter/macros.rs
@@ -384,6 +384,15 @@ macro_rules! iterator {
 
         #[unstable(feature = "trusted_len", issue = "37572")]
         unsafe impl<T> TrustedLen for $name<'_, T> {}
+
+        impl<'a, T> UncheckedIterator for $name<'a, T> {
+            unsafe fn next_unchecked(&mut self) -> $elem {
+                // SAFETY: The caller promised there's at least one more item.
+                unsafe {
+                    next_unchecked!(self)
+                }
+            }
+        }
     }
 }
 
diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
index f268fe3ae7b..5327e4f8139 100644
--- a/library/core/tests/array.rs
+++ b/library/core/tests/array.rs
@@ -700,3 +700,28 @@ fn array_into_iter_rfold() {
     let s = it.rfold(10, |a, b| 10 * a + b);
     assert_eq!(s, 10432);
 }
+
+#[cfg(not(panic = "abort"))]
+#[test]
+fn array_map_drops_unmapped_elements_on_panic() {
+    struct DropCounter<'a>(usize, &'a AtomicUsize);
+    impl Drop for DropCounter<'_> {
+        fn drop(&mut self) {
+            self.1.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    const MAX: usize = 11;
+    for panic_after in 0..MAX {
+        let counter = AtomicUsize::new(0);
+        let a = array::from_fn::<_, 11, _>(|i| DropCounter(i, &counter));
+        let success = std::panic::catch_unwind(|| {
+            let _ = a.map(|x| {
+                assert!(x.0 < panic_after);
+                assert_eq!(counter.load(Ordering::SeqCst), x.0);
+            });
+        });
+        assert!(success.is_err());
+        assert_eq!(counter.load(Ordering::SeqCst), MAX);
+    }
+}
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 37345c1d381..62566a9502d 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -582,6 +582,9 @@ fn test_next_chunk() {
     assert_eq!(it.next_chunk().unwrap(), []);
     assert_eq!(it.next_chunk().unwrap(), [4, 5, 6, 7, 8, 9]);
     assert_eq!(it.next_chunk::<4>().unwrap_err().as_slice(), &[10, 11]);
+
+    let mut it = std::iter::repeat_with(|| panic!());
+    assert_eq!(it.next_chunk::<0>().unwrap(), []);
 }
 
 // just tests by whether or not this compiles
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
index 662c9e36694..4e6bcba5e20 100644
--- a/src/ci/stage-build.py
+++ b/src/ci/stage-build.py
@@ -211,7 +211,8 @@ Duration = float
 TimerSection = Union[Duration, "Timer"]
 
 
-def iterate_sections(section: TimerSection, name: str, level: int = 0) -> Iterator[Tuple[int, str, Duration]]:
+def iterate_sections(section: TimerSection, name: str, level: int = 0) -> Iterator[
+    Tuple[int, str, Duration]]:
     """
     Hierarchically iterate the sections of a timer, in a depth-first order.
     """
@@ -239,7 +240,7 @@ class Timer:
         start = get_timestamp()
         exc = None
 
-        child_timer = Timer(parent_names=self.parent_names + (name, ))
+        child_timer = Timer(parent_names=self.parent_names + (name,))
         full_name = " > ".join(child_timer.parent_names)
         try:
             LOGGER.info(f"Section `{full_name}` starts")
@@ -648,6 +649,16 @@ def print_binary_sizes(pipeline: Pipeline):
         LOGGER.info(f"Rustc binary size\n{output.getvalue()}")
 
 
+def print_free_disk_space(pipeline: Pipeline):
+    usage = shutil.disk_usage(pipeline.opt_artifacts())
+    total = usage.total
+    used = usage.used
+    free = usage.free
+
+    logging.info(
+        f"Free disk space: {format_bytes(free)} out of total {format_bytes(total)} ({(used / total) * 100:.2f}% used)")
+
+
 def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]):
     # Clear and prepare tmp directory
     shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True)
@@ -666,6 +677,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
 
         with stage1.section("Gather profiles"):
             gather_llvm_profiles(pipeline)
+        print_free_disk_space(pipeline)
 
     clear_llvm_files(pipeline)
     final_build_args += [
@@ -683,6 +695,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
 
         with stage2.section("Gather profiles"):
             gather_rustc_profiles(pipeline)
+        print_free_disk_space(pipeline)
 
     clear_llvm_files(pipeline)
     final_build_args += [
@@ -702,6 +715,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
             with stage3.section("Gather profiles"):
                 gather_llvm_bolt_profiles(pipeline)
 
+        print_free_disk_space(pipeline)
         clear_llvm_files(pipeline)
         final_build_args += [
             "--llvm-bolt-profile-use",
@@ -733,5 +747,6 @@ if __name__ == "__main__":
         raise e
     finally:
         timer.print_stats()
+        print_free_disk_space(pipeline)
 
     print_binary_sizes(pipeline)
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index a26c25c9782..7e16c4701be 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -4,6 +4,7 @@ use rustc_data_structures::sync::{self, Lrc};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
+use rustc_errors::TerminalUrl;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
@@ -144,6 +145,7 @@ pub(crate) fn new_handler(
                     diagnostic_width,
                     false,
                     unstable_opts.track_diagnostics,
+                    TerminalUrl::No,
                 )
                 .ui_testing(unstable_opts.ui_testing),
             )
@@ -163,6 +165,7 @@ pub(crate) fn new_handler(
                     diagnostic_width,
                     false,
                     unstable_opts.track_diagnostics,
+                    TerminalUrl::No,
                 )
                 .ui_testing(unstable_opts.ui_testing),
             )
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 37a1005cba1..57c41b57311 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1,7 +1,7 @@
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
+use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError, TerminalUrl};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
 use rustc_interface::interface;
@@ -557,6 +557,7 @@ pub(crate) fn make_test(
                 Some(80),
                 false,
                 false,
+                TerminalUrl::No,
             )
             .supports_color();
 
@@ -571,6 +572,7 @@ pub(crate) fn make_test(
                 None,
                 false,
                 false,
+                TerminalUrl::No,
             );
 
             // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
@@ -756,6 +758,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
                 None,
                 false,
                 false,
+                TerminalUrl::No,
             );
 
             let handler = Handler::with_emitter(false, None, Box::new(emitter));
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 1644d1c5a29..3c10eb524d7 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -96,13 +96,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, to
     );
 
     if tooltip != Tooltip::None {
+        let edition_code;
         write!(
             out,
-            "<div class='tooltip'{}>ⓘ</div>",
-            if let Tooltip::Edition(edition_info) = tooltip {
-                format!(" data-edition=\"{}\"", edition_info)
-            } else {
-                String::new()
+            "<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
+            match tooltip {
+                Tooltip::Ignore => "This example is not tested",
+                Tooltip::CompileFail => "This example deliberately fails to compile",
+                Tooltip::ShouldPanic => "This example panics",
+                Tooltip::Edition(edition) => {
+                    edition_code = format!("This example runs with edition {edition}");
+                    &edition_code
+                }
+                Tooltip::None => unreachable!(),
             },
         );
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 6a9a7a6b1a0..2086faf78ac 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1310,7 +1310,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
     if has_notable_trait {
         cx.types_with_notable_traits.insert(ty.clone());
         Some(format!(
-            " <a href=\"#\" class=\"notable-traits\" data-ty=\"{ty}\">ⓘ</a>",
+            " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
             ty = Escape(&format!("{:#}", ty.print(cx))),
         ))
     } else {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 4f8f00f298a..476dd606680 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -715,8 +715,8 @@ h2.small-section-header > .anchor {
 .main-heading a:hover,
 .example-wrap > pre.rust a:hover,
 .all-items a:hover,
-.docblock a:not(.test-arrow):not(.scrape-help):hover,
-.docblock-short a:not(.test-arrow):not(.scrape-help):hover,
+.docblock a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
+.docblock-short a:not(.test-arrow):not(.scrape-help):not(.tooltip):hover,
 .item-info a {
 	text-decoration: underline;
 }
@@ -1109,44 +1109,8 @@ pre.rust .doccomment {
 	display: block;
 	left: -25px;
 	top: 5px;
-}
-
-.example-wrap .tooltip:hover::after {
-	padding: 5px 3px 3px 3px;
-	border-radius: 6px;
-	margin-left: 5px;
-	font-size: 1rem;
-	border: 1px solid var(--border-color);
-	position: absolute;
-	width: max-content;
-	top: -2px;
-	z-index: 1;
-	background-color: var(--tooltip-background-color);
-	color: var(--tooltip-color);
-}
-
-.example-wrap .tooltip:hover::before {
-	content: " ";
-	position: absolute;
-	top: 50%;
-	left: 16px;
-	margin-top: -5px;
-	z-index: 1;
-	border: 5px solid transparent;
-	border-right-color: var(--tooltip-background-color);
-}
-
-.example-wrap.ignore .tooltip:hover::after {
-	content: "This example is not tested";
-}
-.example-wrap.compile_fail .tooltip:hover::after {
-	content: "This example deliberately fails to compile";
-}
-.example-wrap.should_panic .tooltip:hover::after {
-	content: "This example panics";
-}
-.example-wrap.edition .tooltip:hover::after {
-	content: "This code runs with edition " attr(data-edition);
+	margin: 0;
+	line-height: 1;
 }
 
 .example-wrap.compile_fail .tooltip,
@@ -1213,7 +1177,7 @@ a.test-arrow:hover {
 	border-right: 3px solid var(--target-border-color);
 }
 
-.notable-traits {
+.code-header a.tooltip {
 	color: inherit;
 	margin-right: 15px;
 	position: relative;
@@ -1222,7 +1186,7 @@ a.test-arrow:hover {
 /* placeholder thunk so that the mouse can easily travel from "(i)" to popover
 	the resulting "hover tunnel" is a stepped triangle, approximating
 	https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */
-.notable-traits:hover::after {
+a.tooltip:hover::after {
 	position: absolute;
 	top: calc(100% - 10px);
 	left: -15px;
@@ -1231,11 +1195,11 @@ a.test-arrow:hover {
 	content: "\00a0";
 }
 
-.notable .content {
+.popover.tooltip .content {
 	margin: 0.25em 0.5em;
 }
 
-.notable .content pre, .notable .content code {
+.popover.tooltip .content pre, .popover.tooltip .content code {
 	background: transparent;
 	margin: 0;
 	padding: 0;
@@ -1243,7 +1207,7 @@ a.test-arrow:hover {
 	white-space: pre-wrap;
 }
 
-.notable .content > h3:first-child {
+.popover.tooltip .content > h3:first-child {
 	margin: 0 0 5px 0;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index b5a2cf7f28b..472a725f053 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -74,8 +74,6 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
 	--target-background-color: rgba(255, 236, 164, 0.06);
 	--target-border-color: rgba(255, 180, 76, 0.85);
-	--tooltip-background-color: #314559;
-	--tooltip-color: #c5c5c5;
 	--kbd-color: #c5c5c5;
 	--kbd-background: #314559;
 	--kbd-box-shadow-color: #5c6773;
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index b84d87c4a54..5612bde96a8 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -69,8 +69,6 @@
 	--test-arrow-hover-background-color: #4e8bca;
 	--target-background-color: #494a3d;
 	--target-border-color: #bb7410;
-	--tooltip-background-color: #000;
-	--tooltip-color: #fff;
 	--kbd-color: #000;
 	--kbd-background: #fafbfc;
 	--kbd-box-shadow-color: #c6cbd1;
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 342274e6767..34b35c405a8 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -69,8 +69,6 @@
 	--test-arrow-hover-background-color: #4e8bca;
 	--target-background-color: #fdffd3;
 	--target-border-color: #ad7c37;
-	--tooltip-background-color: #000;
-	--tooltip-color: #fff;
 	--kbd-color: #000;
 	--kbd-background: #fafbfc;
 	--kbd-box-shadow-color: #c6cbd1;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index aa4d65b4bfb..5e8c0e8d10c 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -378,7 +378,7 @@ function loadCss(cssUrl) {
         }
         ev.preventDefault();
         searchState.defocus();
-        window.hideAllModals(true); // true = reset focus for notable traits
+        window.hideAllModals(true); // true = reset focus for tooltips
     }
 
     function handleShortcut(ev) {
@@ -784,17 +784,17 @@ function loadCss(cssUrl) {
             // we need to switch away from mobile mode and make the main content area scrollable.
             hideSidebar();
         }
-        if (window.CURRENT_NOTABLE_ELEMENT) {
-            // As a workaround to the behavior of `contains: layout` used in doc togglers, the
-            // notable traits popup is positioned using javascript.
+        if (window.CURRENT_TOOLTIP_ELEMENT) {
+            // As a workaround to the behavior of `contains: layout` used in doc togglers,
+            // tooltip popovers are positioned using javascript.
             //
             // This means when the window is resized, we need to redo the layout.
-            const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE;
-            const force_visible = base.NOTABLE_FORCE_VISIBLE;
-            hideNotable(false);
+            const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
+            const force_visible = base.TOOLTIP_FORCE_VISIBLE;
+            hideTooltip(false);
             if (force_visible) {
-                showNotable(base);
-                base.NOTABLE_FORCE_VISIBLE = true;
+                showTooltip(base);
+                base.TOOLTIP_FORCE_VISIBLE = true;
             }
         }
     });
@@ -822,27 +822,35 @@ function loadCss(cssUrl) {
         });
     });
 
-    function showNotable(e) {
-        if (!window.NOTABLE_TRAITS) {
+    function showTooltip(e) {
+        const notable_ty = e.getAttribute("data-notable-ty");
+        if (!window.NOTABLE_TRAITS && notable_ty) {
             const data = document.getElementById("notable-traits-data");
             if (data) {
                 window.NOTABLE_TRAITS = JSON.parse(data.innerText);
             } else {
-                throw new Error("showNotable() called on page without any notable traits!");
+                throw new Error("showTooltip() called with notable without any notable traits!");
             }
         }
-        if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) {
+        if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
             // Make this function idempotent.
             return;
         }
         window.hideAllModals(false);
-        const ty = e.getAttribute("data-ty");
         const wrapper = document.createElement("div");
-        wrapper.innerHTML = "<div class=\"content\">" + window.NOTABLE_TRAITS[ty] + "</div>";
-        wrapper.className = "notable popover";
+        if (notable_ty) {
+            wrapper.innerHTML = "<div class=\"content\">" +
+                window.NOTABLE_TRAITS[notable_ty] + "</div>";
+        } else if (e.getAttribute("title") !== undefined) {
+            const titleContent = document.createElement("div");
+            titleContent.className = "content";
+            titleContent.appendChild(document.createTextNode(e.getAttribute("title")));
+            wrapper.appendChild(titleContent);
+        }
+        wrapper.className = "tooltip popover";
         const focusCatcher = document.createElement("div");
         focusCatcher.setAttribute("tabindex", "0");
-        focusCatcher.onfocus = hideNotable;
+        focusCatcher.onfocus = hideTooltip;
         wrapper.appendChild(focusCatcher);
         const pos = e.getBoundingClientRect();
         // 5px overlap so that the mouse can easily travel from place to place
@@ -864,62 +872,62 @@ function loadCss(cssUrl) {
             );
         }
         wrapper.style.visibility = "";
-        window.CURRENT_NOTABLE_ELEMENT = wrapper;
-        window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e;
+        window.CURRENT_TOOLTIP_ELEMENT = wrapper;
+        window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
         wrapper.onpointerleave = function(ev) {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
-                hideNotable(true);
+            if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
+                hideTooltip(true);
             }
         };
     }
 
-    function notableBlurHandler(event) {
-        if (window.CURRENT_NOTABLE_ELEMENT &&
-            !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT) &&
-            !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT) &&
-            !elemIsInParent(document.activeElement, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE) &&
-            !elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE)
+    function tooltipBlurHandler(event) {
+        if (window.CURRENT_TOOLTIP_ELEMENT &&
+            !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT) &&
+            !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT) &&
+            !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE) &&
+            !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE)
         ) {
             // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
-            // When I click the button on an already-opened notable trait popover, Safari
+            // When I click the button on an already-opened tooltip popover, Safari
             // hides the popover and then immediately shows it again, while everyone else hides it
             // and it stays hidden.
             //
             // To work around this, make sure the click finishes being dispatched before
-            // hiding the popover. Since `hideNotable()` is idempotent, this makes Safari behave
+            // hiding the popover. Since `hideTooltip()` is idempotent, this makes Safari behave
             // consistently with the other two.
-            setTimeout(() => hideNotable(false), 0);
+            setTimeout(() => hideTooltip(false), 0);
         }
     }
 
-    function hideNotable(focus) {
-        if (window.CURRENT_NOTABLE_ELEMENT) {
-            if (window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE) {
+    function hideTooltip(focus) {
+        if (window.CURRENT_TOOLTIP_ELEMENT) {
+            if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
                 if (focus) {
-                    window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.focus();
+                    window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
                 }
-                window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false;
+                window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
             }
             const body = document.getElementsByTagName("body")[0];
-            body.removeChild(window.CURRENT_NOTABLE_ELEMENT);
-            window.CURRENT_NOTABLE_ELEMENT = null;
+            body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+            window.CURRENT_TOOLTIP_ELEMENT = null;
         }
     }
 
-    onEachLazy(document.getElementsByClassName("notable-traits"), e => {
+    onEachLazy(document.getElementsByClassName("tooltip"), e => {
         e.onclick = function() {
-            this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true;
-            if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) {
-                hideNotable(true);
+            this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
+            if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
+                hideTooltip(true);
             } else {
-                showNotable(this);
-                window.CURRENT_NOTABLE_ELEMENT.setAttribute("tabindex", "0");
-                window.CURRENT_NOTABLE_ELEMENT.focus();
-                window.CURRENT_NOTABLE_ELEMENT.onblur = notableBlurHandler;
+                showTooltip(this);
+                window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
+                window.CURRENT_TOOLTIP_ELEMENT.focus();
+                window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
             }
             return false;
         };
@@ -928,16 +936,16 @@ function loadCss(cssUrl) {
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            showNotable(this);
+            showTooltip(this);
         };
         e.onpointerleave = function(ev) {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
-            if (!this.NOTABLE_FORCE_VISIBLE &&
-                !elemIsInParent(ev.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
-                hideNotable(true);
+            if (!this.TOOLTIP_FORCE_VISIBLE &&
+                !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
+                hideTooltip(true);
             }
         };
     });
@@ -1039,14 +1047,14 @@ function loadCss(cssUrl) {
     }
 
     /**
-     * Hide popover menus, notable trait tooltips, and the sidebar (if applicable).
+     * Hide popover menus, clickable tooltips, and the sidebar (if applicable).
      *
-     * Pass "true" to reset focus for notable traits.
+     * Pass "true" to reset focus for tooltip popovers.
      */
     window.hideAllModals = function(switchFocus) {
         hideSidebar();
         window.hidePopoverMenus();
-        hideNotable(switchFocus);
+        hideTooltip(switchFocus);
     };
 
     /**
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 127201b72e2..0b31e20fc87 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -11,7 +11,7 @@ use rustc_ast::token::CommentKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Applicability, Handler, SuggestionStyle};
+use rustc_errors::{Applicability, Handler, SuggestionStyle, TerminalUrl};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Expr};
@@ -717,6 +717,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
                     None,
                     false,
                     false,
+                    TerminalUrl::No,
                 );
                 let handler = Handler::with_emitter(false, None, Box::new(emitter));
                 let sess = ParseSess::with_span_handler(handler, sm);
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index d521e8d8839..e45835efe74 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -220,6 +220,7 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         None,
         false,
         false,
+        rustc_errors::TerminalUrl::No,
     ));
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
 
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 6bfec79cd70..9014026b0aa 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use rustc_data_structures::sync::{Lrc, Send};
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::translation::Translate;
-use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
+use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel, TerminalUrl};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
     source_map::{FilePathMapping, SourceMap},
@@ -135,6 +135,7 @@ fn default_handler(
             None,
             false,
             false,
+            TerminalUrl::No,
         ))
     };
     Handler::with_emitter(
diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs
new file mode 100644
index 00000000000..9298e89e397
--- /dev/null
+++ b/tests/codegen/array-map.rs
@@ -0,0 +1,49 @@
+// compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3
+// no-system-llvm
+// only-x86_64
+// ignore-debug (the extra assertions get in the way)
+
+#![crate_type = "lib"]
+#![feature(array_zip)]
+
+// CHECK-LABEL: @short_integer_map
+#[no_mangle]
+pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] {
+    // CHECK: load <8 x i32>
+    // CHECK: shl <8 x i32>
+    // CHECK: or <8 x i32>
+    // CHECK: store <8 x i32>
+    x.map(|x| 2 * x + 1)
+}
+
+// CHECK-LABEL: @short_integer_zip_map
+#[no_mangle]
+pub fn short_integer_zip_map(x: [u32; 8], y: [u32; 8]) -> [u32; 8] {
+    // CHECK: %[[A:.+]] = load <8 x i32>
+    // CHECK: %[[B:.+]] = load <8 x i32>
+    // CHECK: sub <8 x i32> %[[A]], %[[B]]
+    // CHECK: store <8 x i32>
+    x.zip(y).map(|(x, y)| x - y)
+}
+
+// This test is checking that LLVM can SRoA away a bunch of the overhead,
+// like fully moving the iterators to registers.  Notably, previous implementations
+// of `map` ended up `alloca`ing the whole `array::IntoIterator`, meaning both a
+// hard-to-eliminate `memcpy` and that the iteration counts needed to be written
+// out to stack every iteration, even for infallible operations on `Copy` types.
+//
+// This is still imperfect, as there's more copies than would be ideal,
+// but hopefully work like #103830 will improve that in future,
+// and update this test to be stricter.
+//
+// CHECK-LABEL: @long_integer_map
+#[no_mangle]
+pub fn long_integer_map(x: [u32; 64]) -> [u32; 64] {
+    // CHECK: start:
+    // CHECK-NEXT: alloca [64 x i32]
+    // CHECK-NEXT: alloca %"core::mem::manually_drop::ManuallyDrop<[u32; 64]>"
+    // CHECK-NOT: alloca
+    // CHECK: mul <{{[0-9]+}} x i32>
+    // CHECK: add <{{[0-9]+}} x i32>
+    x.map(|x| 13 * x + 7)
+}
diff --git a/tests/codegen/autovectorize-f32x4.rs b/tests/codegen/autovectorize-f32x4.rs
index 6b09c8fc998..9ecea53f1c0 100644
--- a/tests/codegen/autovectorize-f32x4.rs
+++ b/tests/codegen/autovectorize-f32x4.rs
@@ -1,6 +1,7 @@
-// compile-flags: -C opt-level=3
+// compile-flags: -C opt-level=3 -Z merge-functions=disabled
 // only-x86_64
 #![crate_type = "lib"]
+#![feature(array_zip)]
 
 // CHECK-LABEL: @auto_vectorize_direct
 #[no_mangle]
@@ -30,3 +31,13 @@ pub fn auto_vectorize_loop(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
     }
     c
 }
+
+// CHECK-LABEL: @auto_vectorize_array_zip_map
+#[no_mangle]
+pub fn auto_vectorize_array_zip_map(a: [f32; 4], b: [f32; 4]) -> [f32; 4] {
+// CHECK: load <4 x float>
+// CHECK: load <4 x float>
+// CHECK: fadd <4 x float>
+// CHECK: store <4 x float>
+    a.zip(b).map(|(a, b)| a + b)
+}
diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml
index a3ef4e77b54..36b67073a03 100644
--- a/tests/rustdoc-gui/codeblock-tooltip.goml
+++ b/tests/rustdoc-gui/codeblock-tooltip.goml
@@ -30,24 +30,16 @@ define-function: (
             ".docblock .example-wrap.compile_fail",
             {"border-left": "2px solid rgb(255, 0, 0)"},
         )
-        assert-css: (
-            ".docblock .example-wrap.compile_fail .tooltip::after",
-            {
-                "content": '"This example deliberately fails to compile"',
-                "padding": "5px 3px 3px",
-                "background-color": |background|,
-                "color": |color|,
-                "border": "1px solid " + |border|,
-            },
-        )
-        assert-css: (
-            ".docblock .example-wrap.compile_fail .tooltip::before",
-            {
-                "border-width": "5px",
-                "border-style": "solid",
-                "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
-            },
-        )
+        click: ".docblock .example-wrap.compile_fail .tooltip"
+        assert-text: (
+            ".popover.tooltip",
+            "This example deliberately fails to compile"
+        )
+        assert-css: (".popover.tooltip", {
+            "color": |color|,
+            "background-color": |background|,
+            "border-color": |border|,
+        })
 
         // should_panic block
         assert-css: (
@@ -69,24 +61,16 @@ define-function: (
             ".docblock .example-wrap.should_panic",
             {"border-left": "2px solid rgb(255, 0, 0)"},
         )
-        assert-css: (
-            ".docblock .example-wrap.should_panic .tooltip::after",
-            {
-                "content": '"This example panics"',
-                "padding": "5px 3px 3px",
-                "background-color": |background|,
-                "color": |color|,
-                "border": "1px solid " + |border|,
-            },
-        )
-        assert-css: (
-            ".docblock .example-wrap.should_panic .tooltip::before",
-            {
-                "border-width": "5px",
-                "border-style": "solid",
-                "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
-            },
+        click: ".docblock .example-wrap.should_panic .tooltip"
+        assert-text: (
+            ".popover.tooltip",
+            "This example panics"
         )
+        assert-css: (".popover.tooltip", {
+            "color": |color|,
+            "background-color": |background|,
+            "border-color": |border|,
+        })
 
         // ignore block
         assert-css: (
@@ -108,42 +92,36 @@ define-function: (
             ".docblock .example-wrap.ignore",
             {"border-left": "2px solid rgb(255, 142, 0)"},
         )
-        assert-css: (
-            ".docblock .example-wrap.ignore .tooltip::after",
-            {
-                "content": '"This example is not tested"',
-                "padding": "5px 3px 3px",
-                "background-color": |background|,
-                "color": |color|,
-                "border": "1px solid " + |border|,
-            },
-        )
-        assert-css: (
-            ".docblock .example-wrap.ignore .tooltip::before",
-            {
-                "border-width": "5px",
-                "border-style": "solid",
-                "border-color": "rgba(0, 0, 0, 0) " + |background| + " rgba(0, 0, 0, 0) rgba(0, 0, 0, 0)",
-            },
-        )
+        click: ".docblock .example-wrap.ignore .tooltip"
+        assert-text: (
+            ".popover.tooltip",
+            "This example is not tested"
+        )
+        assert-css: (".popover.tooltip", {
+            "color": |color|,
+            "background-color": |background|,
+            "border-color": |border|,
+        })
+        click: ".docblock .example-wrap.ignore .tooltip"
+        assert-false: ".popover.tooltip"
     },
 )
 
 call-function: ("check-colors", {
     "theme": "ayu",
-    "background": "rgb(49, 69, 89)",
+    "background": "rgb(15, 20, 25)",
     "color": "rgb(197, 197, 197)",
     "border": "rgb(92, 103, 115)",
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "background": "rgb(0, 0, 0)",
-    "color": "rgb(255, 255, 255)",
+    "background": "rgb(53, 53, 53)",
+    "color": "rgb(221, 221, 221)",
     "border": "rgb(224, 224, 224)",
 })
 call-function: ("check-colors", {
     "theme": "light",
-    "background": "rgb(0, 0, 0)",
-    "color": "rgb(255, 255, 255)",
+    "background": "rgb(255, 255, 255)",
+    "color": "rgb(0, 0, 0)",
     "border": "rgb(224, 224, 224)",
 })
diff --git a/tests/rustdoc-gui/notable-trait.goml b/tests/rustdoc-gui/notable-trait.goml
index b4fa7d0dbf0..20728915199 100644
--- a/tests/rustdoc-gui/notable-trait.goml
+++ b/tests/rustdoc-gui/notable-trait.goml
@@ -6,13 +6,13 @@ size: (1100, 600)
 // Checking they have the same y position.
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("y"),
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("x"),
 )
 // The `i` should be *after* the type.
@@ -21,33 +21,33 @@ assert-position: (
     {"x": 677},
 )
 assert-position: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     {"x": 955},
 )
 // The tooltip should be below the `i`
 // Also, clicking the tooltip should bring its text into the DOM
-assert-count: ("//*[@class='notable popover']", 0)
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+assert-count: ("//*[@class='tooltip popover']", 0)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 compare-elements-position-near: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@class='notable popover']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
+    "//*[@class='tooltip popover']",
     {"y": 30}
 )
 compare-elements-position-false: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@class='notable popover']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
+    "//*[@class='tooltip popover']",
     ("x")
 )
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 move-cursor-to: "//h1"
-assert-count: ("//*[@class='notable popover']", 0)
+assert-count: ("//*[@class='tooltip popover']", 0)
 
 // Now only the `i` should be on the next line.
 size: (1055, 600)
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("y", "x"),
 )
 
@@ -56,13 +56,13 @@ size: (980, 600)
 // Checking they have the same y position.
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("y"),
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("x"),
 )
 // The `i` should be *after* the type.
@@ -71,7 +71,7 @@ assert-position: (
     {"x": 245},
 )
 assert-position: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     {"x": 523},
 )
 
@@ -80,13 +80,13 @@ size: (650, 600)
 // Checking they have the same y position.
 compare-elements-position: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("y"),
 )
 // Checking they don't have the same x position.
 compare-elements-position-false: (
     "//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     ("x"),
 )
 // The `i` should be *after* the type.
@@ -95,29 +95,29 @@ assert-position: (
     {"x": 15},
 )
 assert-position: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
     {"x": 293},
 )
 // The tooltip should STILL be below `i`
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 compare-elements-position-near: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@class='notable popover']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
+    "//*[@class='tooltip popover']",
     {"y": 30}
 )
 compare-elements-position-false: (
-    "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
-    "//*[@class='notable popover']",
+    "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
+    "//*[@class='tooltip popover']",
     ("x")
 )
 assert-position: (
-    "//*[@class='notable popover']",
+    "//*[@class='tooltip popover']",
     {"x": 0}
 )
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
 move-cursor-to: "//h1"
-assert-count: ("//*[@class='notable popover']", 0)
+assert-count: ("//*[@class='tooltip popover']", 0)
 
 // Now check the colors.
 define-function: (
@@ -133,26 +133,26 @@ define-function: (
         // We reload the page so the local storage settings are being used.
         reload:
 
-        move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-        assert-count: (".notable.popover", 1)
+        move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+        assert-count: (".tooltip.popover", 1)
 
         assert-css: (
-             ".notable.popover h3",
+             ".tooltip.popover h3",
              {"color": |header_color|},
              ALL,
         )
         assert-css: (
-             ".notable.popover pre",
+             ".tooltip.popover pre",
              {"color": |content_color|},
              ALL,
         )
         assert-css: (
-             ".notable.popover pre a.struct",
+             ".tooltip.popover pre a.struct",
              {"color": |type_color|},
              ALL,
         )
         assert-css: (
-             ".notable.popover pre a.trait",
+             ".tooltip.popover pre a.trait",
              {"color": |trait_color|},
              ALL,
         )
@@ -195,24 +195,24 @@ call-function: (
 reload:
 
 // Check that pressing escape works
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-move-cursor-to: "//*[@class='notable popover']"
-assert-count: ("//*[@class='notable popover']", 1)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+move-cursor-to: "//*[@class='tooltip popover']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 press-key: "Escape"
-assert-count: ("//*[@class='notable popover']", 0)
-assert: "#method\.create_an_iterator_from_read .notable-traits:focus"
+assert-count: ("//*[@class='tooltip popover']", 0)
+assert: "#method\.create_an_iterator_from_read .tooltip:focus"
 
 // Check that clicking outside works.
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 click: ".search-input"
-assert-count: ("//*[@class='notable popover']", 0)
-assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
+assert-count: ("//*[@class='tooltip popover']", 0)
+assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
 
 // Check that pressing tab over and over works.
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-move-cursor-to: "//*[@class='notable popover']"
-assert-count: ("//*[@class='notable popover']", 1)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+move-cursor-to: "//*[@class='tooltip popover']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 press-key: "Tab"
 press-key: "Tab"
 press-key: "Tab"
@@ -220,8 +220,8 @@ press-key: "Tab"
 press-key: "Tab"
 press-key: "Tab"
 press-key: "Tab"
-assert-count: ("//*[@class='notable popover']", 0)
-assert: "#method\.create_an_iterator_from_read .notable-traits:focus"
+assert-count: ("//*[@class='tooltip popover']", 0)
+assert: "#method\.create_an_iterator_from_read .tooltip:focus"
 
 // Now we check that the focus isn't given back to the wrong item when opening
 // another popover.
@@ -231,8 +231,8 @@ click: "#method\.create_an_iterator_from_read .fn"
 assert-window-property-false: {"scrollY": |scroll|}
 // Store the new position.
 store-window-property: (scroll, "scrollY")
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-wait-for: "//*[@class='notable popover']"
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+wait-for: "//*[@class='tooltip popover']"
 click: "#settings-menu a"
 click: ".search-input"
 // We ensure we didn't come back to the previous focused item.
@@ -245,8 +245,8 @@ click: "#method\.create_an_iterator_from_read .fn"
 assert-window-property-false: {"scrollY": |scroll|}
 // Store the new position.
 store-window-property: (scroll, "scrollY")
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-wait-for: "//*[@class='notable popover']"
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+wait-for: "//*[@class='tooltip popover']"
 click: "#settings-menu a"
 press-key: "Escape"
 // We ensure we didn't come back to the previous focused item.
@@ -254,23 +254,23 @@ assert-window-property-false: {"scrollY": |scroll|}
 
 // Opening the mobile sidebar should close the popover.
 size: (650, 600)
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 click: ".sidebar-menu-toggle"
 assert: "//*[@class='sidebar shown']"
-assert-count: ("//*[@class='notable popover']", 0)
-assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
-// Clicking a notable popover should close the sidebar.
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+assert-count: ("//*[@class='tooltip popover']", 0)
+assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
+// Clicking a notable trait tooltip popover should close the sidebar.
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 assert-false: "//*[@class='sidebar shown']"
 
 // Also check the focus handling for the help button.
 size: (1100, 600)
 reload:
-assert-count: ("//*[@class='notable popover']", 0)
-click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
-assert-count: ("//*[@class='notable popover']", 1)
+assert-count: ("//*[@class='tooltip popover']", 0)
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
+assert-count: ("//*[@class='tooltip popover']", 1)
 click: "#help-button a"
-assert-count: ("//*[@class='notable popover']", 0)
-assert-false: "#method\.create_an_iterator_from_read .notable-traits:focus"
+assert-count: ("//*[@class='tooltip popover']", 0)
+assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"
diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout
index 6c1684201a2..96329f31723 100644
--- a/tests/rustdoc-ui/z-help.stdout
+++ b/tests/rustdoc-ui/z-help.stdout
@@ -176,6 +176,7 @@
     -Z                 symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
     -Z                                   teach=val -- show extended diagnostic help (default: no)
     -Z                               temps-dir=val -- the directory the intermediate files are written to
+    -Z                           terminal-urls=val -- use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output
     -Z                                 thinlto=val -- enable ThinLTO when possible
     -Z                           thir-unsafeck=val -- use the THIR unsafety checker (default: no)
     -Z                                 threads=val -- use a thread pool with N threads
diff --git a/tests/rustdoc/codeblock-title.rs b/tests/rustdoc/codeblock-title.rs
index b9b0b0d1abf..761afb8bd08 100644
--- a/tests/rustdoc/codeblock-title.rs
+++ b/tests/rustdoc/codeblock-title.rs
@@ -3,7 +3,7 @@
 // @has foo/fn.bar.html '//*[@class="example-wrap compile_fail"]/*[@class="tooltip"]' "ⓘ"
 // @has foo/fn.bar.html '//*[@class="example-wrap ignore"]/*[@class="tooltip"]' "ⓘ"
 // @has foo/fn.bar.html '//*[@class="example-wrap should_panic"]/*[@class="tooltip"]' "ⓘ"
-// @has foo/fn.bar.html '//*[@data-edition="2018"]' "ⓘ"
+// @has foo/fn.bar.html '//*[@title="This example runs with edition 2018"]' "ⓘ"
 
 /// foo
 ///
diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/doc-notable_trait.rs
index 279faf55401..d8941769fa6 100644
--- a/tests/rustdoc/doc-notable_trait.rs
+++ b/tests/rustdoc/doc-notable_trait.rs
@@ -9,7 +9,7 @@ impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
 #[doc(notable_trait)]
 pub trait SomeTrait {
     // @has doc_notable_trait/trait.SomeTrait.html
-    // @has - '//a[@class="notable-traits"]/@data-ty' 'Wrapper<Self>'
+    // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<Self>'
     // @snapshot wrap-me - '//script[@id="notable-traits-data"]'
     fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
         Wrapper {
@@ -23,7 +23,7 @@ impl SomeTrait for SomeStruct {}
 
 impl SomeStruct {
     // @has doc_notable_trait/struct.SomeStruct.html
-    // @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
+    // @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
     // @snapshot some-struct-new - '//script[@id="notable-traits-data"]'
     pub fn new() -> SomeStruct {
         SomeStruct
@@ -31,7 +31,7 @@ impl SomeStruct {
 }
 
 // @has doc_notable_trait/fn.bare_fn.html
-// @has - '//a[@class="notable-traits"]/@data-ty' 'SomeStruct'
+// @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
 // @snapshot bare-fn - '//script[@id="notable-traits-data"]'
 pub fn bare_fn() -> SomeStruct {
     SomeStruct
diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/spotlight-from-dependency.rs
index 090ad187d9c..426759c7bf8 100644
--- a/tests/rustdoc/spotlight-from-dependency.rs
+++ b/tests/rustdoc/spotlight-from-dependency.rs
@@ -3,7 +3,7 @@
 use std::iter::Iterator;
 
 // @has foo/struct.Odd.html
-// @has - '//*[@id="method.new"]//a[@class="notable-traits"]/@data-ty' 'Odd'
+// @has - '//*[@id="method.new"]//a[@class="tooltip"]/@data-notable-ty' 'Odd'
 // @snapshot odd - '//script[@id="notable-traits-data"]'
 pub struct Odd {
     current: usize,
diff --git a/tests/ui/diagnostic-flags/terminal_urls.rs b/tests/ui/diagnostic-flags/terminal_urls.rs
new file mode 100644
index 00000000000..1f04e2aade1
--- /dev/null
+++ b/tests/ui/diagnostic-flags/terminal_urls.rs
@@ -0,0 +1,4 @@
+// compile-flags: -Zterminal-urls=yes
+fn main() {
+    let () = 4; //~ ERROR
+}
diff --git a/tests/ui/diagnostic-flags/terminal_urls.stderr b/tests/ui/diagnostic-flags/terminal_urls.stderr
new file mode 100644
index 00000000000..7f7e69c5d5d
--- /dev/null
+++ b/tests/ui/diagnostic-flags/terminal_urls.stderr
@@ -0,0 +1,11 @@
+error[]8;;https://doc.rust-lang.org/error_codes/E0308.htmlE0308]8;;]: mismatched types
+  --> $DIR/terminal_urls.rs:3:9
+   |
+LL |     let () = 4;
+   |         ^^   - this expression has type `{integer}`
+   |         |
+   |         expected integer, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/span/issue-107353.rs b/tests/ui/span/issue-107353.rs
new file mode 100644
index 00000000000..943f7f0eb19
--- /dev/null
+++ b/tests/ui/span/issue-107353.rs
@@ -0,0 +1,9 @@
+// ignore-tidy-linelength
+// Verify that span interning correctly handles having a span of exactly MAX_LEN length.
+// compile-flags: --crate-type=lib
+// check-pass
+
+#![allow(dead_code)]
+fn a<'a, T>() -> &'a T {
+todo!()////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+}