about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--RELEASES.md4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs50
-rw-r--r--compiler/rustc_parse/src/parser/item.rs10
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs29
-rw-r--r--compiler/rustc_target/src/spec/crt_objects.rs40
-rw-r--r--compiler/rustc_target/src/spec/linux_musl_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs55
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs6
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs4
-rw-r--r--compiler/rustc_target/src/spec/wasm_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs16
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs3
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs11
-rw-r--r--library/core/src/iter/adapters/array_chunks.rs182
-rw-r--r--library/core/src/iter/adapters/mod.rs4
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs45
-rw-r--r--library/core/tests/iter/adapters/array_chunks.rs179
-rw-r--r--library/core/tests/iter/adapters/mod.rs23
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/sys/unix/fs.rs10
-rw-r--r--src/bootstrap/flags.rs1
-rw-r--r--src/bootstrap/setup.rs2
-rw-r--r--src/librustdoc/clean/mod.rs20
-rw-r--r--src/librustdoc/html/highlight.rs184
-rw-r--r--src/librustdoc/html/highlight/fixtures/decorations.html4
-rw-r--r--src/librustdoc/html/highlight/fixtures/dos_line.html2
-rw-r--r--src/librustdoc/html/highlight/fixtures/highlight.html8
-rw-r--r--src/librustdoc/html/highlight/fixtures/sample.html38
-rw-r--r--src/librustdoc/html/highlight/fixtures/union.html10
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css6
-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/test/rustdoc/issue-41783.codeblock.html5
-rw-r--r--src/test/rustdoc/issue-41783.rs8
-rw-r--r--src/test/rustdoc/macro_rules-matchers.rs6
-rw-r--r--src/test/ui/closures/binder/disallow-const.rs6
-rw-r--r--src/test/ui/closures/binder/disallow-const.stderr8
-rw-r--r--src/test/ui/closures/binder/disallow-ty.rs6
-rw-r--r--src/test/ui/closures/binder/disallow-ty.stderr8
-rw-r--r--src/test/ui/coherence/auxiliary/trait-with-const-param.rs1
-rw-r--r--src/test/ui/coherence/const-generics-orphan-check-ok.rs28
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.rs4
-rw-r--r--src/test/ui/consts/assert-type-intrinsics.stderr8
-rw-r--r--src/test/ui/parser/issue-100197-mut-let.fixed6
-rw-r--r--src/test/ui/parser/issue-100197-mut-let.rs6
-rw-r--r--src/test/ui/parser/issue-100197-mut-let.stderr8
-rw-r--r--src/test/ui/parser/issue-99910-const-let-mutually-exclusive.fixed8
-rw-r--r--src/test/ui/parser/issue-99910-const-let-mutually-exclusive.rs8
-rw-r--r--src/test/ui/parser/issue-99910-const-let-mutually-exclusive.stderr14
51 files changed, 940 insertions, 172 deletions
diff --git a/RELEASES.md b/RELEASES.md
index e66bf60b7f7..147ff3561a3 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -27,6 +27,7 @@ Libraries
 - [Extend `ptr::null` and `null_mut` to all thin (including extern) types.][94954]
 - [`impl Read and Write for VecDeque<u8>`.][95632]
 - [STD support for the Nintendo 3DS.][95897]
+- [Use rounding in float to Duration conversion methods.][96051]
 - [Make write/print macros eagerly drop temporaries.][96455]
 - [Implement internal traits that enable `[OsStr]::join`.][96881]
 - [Implement `Hash` for `core::alloc::Layout`.][97034]
@@ -99,6 +100,8 @@ Compatibility Notes
 
 - [`#[link]` attributes are now checked more strictly,][96885] which may introduce
   errors for invalid attribute arguments that were previously ignored.
+- [Rounding is now used when converting a float to a `Duration`.][96051] The converted
+  duration can differ slightly from what it was.
 
 Internal Changes
 ----------------
@@ -118,6 +121,7 @@ and related tools.
 [95818]: https://github.com/rust-lang/rust/pull/95818/
 [95897]: https://github.com/rust-lang/rust/pull/95897/
 [95953]: https://github.com/rust-lang/rust/pull/95953/
+[96051]: https://github.com/rust-lang/rust/pull/96051/
 [96296]: https://github.com/rust-lang/rust/pull/96296/
 [96455]: https://github.com/rust-lang/rust/pull/96455/
 [96737]: https://github.com/rust-lang/rust/pull/96737/
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 953761a7820..7f6947e3c79 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -20,7 +20,7 @@ use rustc_session::utils::NativeLibKind;
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
 use rustc_span::DebuggerVisualizerFile;
-use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
+use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, SanitizerSet, Target};
 
@@ -764,15 +764,15 @@ fn link_natively<'a>(
                 "Linker does not support -static-pie command line option. Retrying with -static instead."
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
-            let self_contained = crt_objects_fallback(sess, crate_type);
+            let self_contained = self_contained(sess, crate_type);
             let opts = &sess.target;
             let pre_objects = if self_contained {
-                &opts.pre_link_objects_fallback
+                &opts.pre_link_objects_self_contained
             } else {
                 &opts.pre_link_objects
             };
             let post_objects = if self_contained {
-                &opts.post_link_objects_fallback
+                &opts.post_link_objects_self_contained
             } else {
                 &opts.post_link_objects
             };
@@ -1556,26 +1556,26 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
     true
 }
 
-/// Whether we link to our own CRT objects instead of relying on gcc to pull them.
+/// Various toolchain components used during linking are used from rustc distribution
+/// instead of being found somewhere on the host system.
 /// We only provide such support for a very limited number of targets.
-fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
+fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
     if let Some(self_contained) = sess.opts.cg.link_self_contained {
         return self_contained;
     }
 
-    match sess.target.crt_objects_fallback {
+    match sess.target.link_self_contained {
+        LinkSelfContainedDefault::False => false,
+        LinkSelfContainedDefault::True => true,
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
         // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
-        Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
-        Some(CrtObjectsFallback::Mingw) => {
+        LinkSelfContainedDefault::Musl => sess.crt_static(Some(crate_type)),
+        LinkSelfContainedDefault::Mingw => {
             sess.host == sess.target
                 && sess.target.vendor != "uwp"
                 && detect_self_contained_mingw(&sess)
         }
-        // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
-        Some(CrtObjectsFallback::Wasm) => true,
-        None => false,
     }
 }
 
@@ -1592,7 +1592,7 @@ fn add_pre_link_objects(
     let opts = &sess.target;
     let empty = Default::default();
     let objects = if self_contained {
-        &opts.pre_link_objects_fallback
+        &opts.pre_link_objects_self_contained
     } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
         &opts.pre_link_objects
     } else {
@@ -1610,9 +1610,11 @@ fn add_post_link_objects(
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target;
-    let objects =
-        if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+    let objects = if self_contained {
+        &sess.target.post_link_objects_self_contained
+    } else {
+        &sess.target.post_link_objects
+    };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
         cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
@@ -1891,12 +1893,12 @@ fn linker_with_args<'a>(
     out_filename: &Path,
     codegen_results: &CodegenResults,
 ) -> Result<Command, ErrorGuaranteed> {
-    let crt_objects_fallback = crt_objects_fallback(sess, crate_type);
+    let self_contained = self_contained(sess, crate_type);
     let cmd = &mut *super::linker::get_linker(
         sess,
         path,
         flavor,
-        crt_objects_fallback,
+        self_contained,
         &codegen_results.crate_info.target_cpu,
     );
     let link_output_kind = link_output_kind(sess, crate_type);
@@ -1923,7 +1925,7 @@ fn linker_with_args<'a>(
     // ------------ Object code and libraries, order-dependent ------------
 
     // Pre-link CRT objects.
-    add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback);
+    add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained);
 
     add_linked_symbol_object(
         cmd,
@@ -2033,7 +2035,7 @@ fn linker_with_args<'a>(
         cmd,
         sess,
         link_output_kind,
-        crt_objects_fallback,
+        self_contained,
         flavor,
         crate_type,
         codegen_results,
@@ -2049,7 +2051,7 @@ fn linker_with_args<'a>(
     // ------------ Object code and libraries, order-dependent ------------
 
     // Post-link CRT objects.
-    add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+    add_post_link_objects(cmd, sess, link_output_kind, self_contained);
 
     // ------------ Late order-dependent options ------------
 
@@ -2066,7 +2068,7 @@ fn add_order_independent_options(
     cmd: &mut dyn Linker,
     sess: &Session,
     link_output_kind: LinkOutputKind,
-    crt_objects_fallback: bool,
+    self_contained: bool,
     flavor: LinkerFlavor,
     crate_type: CrateType,
     codegen_results: &CodegenResults,
@@ -2098,7 +2100,7 @@ fn add_order_independent_options(
     // Make the binary compatible with data execution prevention schemes.
     cmd.add_no_exec();
 
-    if crt_objects_fallback {
+    if self_contained {
         cmd.no_crt_objects();
     }
 
@@ -2127,7 +2129,7 @@ fn add_order_independent_options(
 
     cmd.linker_plugin_lto();
 
-    add_library_search_dirs(cmd, sess, crt_objects_fallback);
+    add_library_search_dirs(cmd, sess, self_contained);
 
     cmd.output_filename(out_filename);
 
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c6dd5e7fda3..83fab0829a1 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1162,6 +1162,16 @@ impl<'a> Parser<'a> {
                     Applicability::MaybeIncorrect,
                 )
                 .emit();
+        } else if self.eat_keyword(kw::Let) {
+            let span = self.prev_token.span;
+            self.struct_span_err(const_span.to(span), "`const` and `let` are mutually exclusive")
+                .span_suggestion(
+                    const_span.to(span),
+                    "remove `let`",
+                    "const",
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
         }
     }
 
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 51bd9d2d386..d8b39a406cc 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -55,6 +55,19 @@ impl<'a> Parser<'a> {
             return Ok(Some(stmt.into_inner()));
         }
 
+        if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
+            self.bump();
+            let mut_let_span = lo.to(self.token.span);
+            self.struct_span_err(mut_let_span, "invalid variable declaration")
+                .span_suggestion(
+                    mut_let_span,
+                    "switch the order of `mut` and `let`",
+                    "let mut",
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
+
         Ok(Some(if self.token.is_keyword(kw::Let) {
             self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
         } else if self.is_kw_followed_by_ident(kw::Mut) {
@@ -247,6 +260,22 @@ impl<'a> Parser<'a> {
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
+
+        if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
+            self.struct_span_err(
+                lo.to(self.token.span),
+                "`const` and `let` are mutually exclusive",
+            )
+            .span_suggestion(
+                lo.to(self.token.span),
+                "remove `let`",
+                "const",
+                Applicability::MaybeIncorrect,
+            )
+            .emit();
+            self.bump();
+        }
+
         let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?;
 
         let (err, ty) = if colon {
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 52ac3622eca..c126390f5a9 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -63,7 +63,7 @@ pub(super) fn all(obj: &'static str) -> CrtObjects {
     ])
 }
 
-pub(super) fn pre_musl_fallback() -> CrtObjects {
+pub(super) fn pre_musl_self_contained() -> CrtObjects {
     new(&[
         (LinkOutputKind::DynamicNoPicExe, &["crt1.o", "crti.o", "crtbegin.o"]),
         (LinkOutputKind::DynamicPicExe, &["Scrt1.o", "crti.o", "crtbeginS.o"]),
@@ -74,7 +74,7 @@ pub(super) fn pre_musl_fallback() -> CrtObjects {
     ])
 }
 
-pub(super) fn post_musl_fallback() -> CrtObjects {
+pub(super) fn post_musl_self_contained() -> CrtObjects {
     new(&[
         (LinkOutputKind::DynamicNoPicExe, &["crtend.o", "crtn.o"]),
         (LinkOutputKind::DynamicPicExe, &["crtendS.o", "crtn.o"]),
@@ -85,7 +85,7 @@ pub(super) fn post_musl_fallback() -> CrtObjects {
     ])
 }
 
-pub(super) fn pre_mingw_fallback() -> CrtObjects {
+pub(super) fn pre_mingw_self_contained() -> CrtObjects {
     new(&[
         (LinkOutputKind::DynamicNoPicExe, &["crt2.o", "rsbegin.o"]),
         (LinkOutputKind::DynamicPicExe, &["crt2.o", "rsbegin.o"]),
@@ -96,7 +96,7 @@ pub(super) fn pre_mingw_fallback() -> CrtObjects {
     ])
 }
 
-pub(super) fn post_mingw_fallback() -> CrtObjects {
+pub(super) fn post_mingw_self_contained() -> CrtObjects {
     all("rsend.o")
 }
 
@@ -108,7 +108,7 @@ pub(super) fn post_mingw() -> CrtObjects {
     all("rsend.o")
 }
 
-pub(super) fn pre_wasi_fallback() -> CrtObjects {
+pub(super) fn pre_wasi_self_contained() -> CrtObjects {
     // Use crt1-command.o instead of crt1.o to enable support for new-style
     // commands. See https://reviews.llvm.org/D81689 for more info.
     new(&[
@@ -120,37 +120,41 @@ pub(super) fn pre_wasi_fallback() -> CrtObjects {
     ])
 }
 
-pub(super) fn post_wasi_fallback() -> CrtObjects {
+pub(super) fn post_wasi_self_contained() -> CrtObjects {
     new(&[])
 }
 
-/// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
+/// Which logic to use to determine whether to use self-contained linking mode
+/// if `-Clink-self-contained` is not specified explicitly.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
-pub enum CrtObjectsFallback {
+pub enum LinkSelfContainedDefault {
+    False,
+    True,
     Musl,
     Mingw,
-    Wasm,
 }
 
-impl FromStr for CrtObjectsFallback {
+impl FromStr for LinkSelfContainedDefault {
     type Err = ();
 
-    fn from_str(s: &str) -> Result<CrtObjectsFallback, ()> {
+    fn from_str(s: &str) -> Result<LinkSelfContainedDefault, ()> {
         Ok(match s {
-            "musl" => CrtObjectsFallback::Musl,
-            "mingw" => CrtObjectsFallback::Mingw,
-            "wasm" => CrtObjectsFallback::Wasm,
+            "false" => LinkSelfContainedDefault::False,
+            "true" | "wasm" => LinkSelfContainedDefault::True,
+            "musl" => LinkSelfContainedDefault::Musl,
+            "mingw" => LinkSelfContainedDefault::Mingw,
             _ => return Err(()),
         })
     }
 }
 
-impl ToJson for CrtObjectsFallback {
+impl ToJson for LinkSelfContainedDefault {
     fn to_json(&self) -> Json {
         match *self {
-            CrtObjectsFallback::Musl => "musl",
-            CrtObjectsFallback::Mingw => "mingw",
-            CrtObjectsFallback::Wasm => "wasm",
+            LinkSelfContainedDefault::False => "false",
+            LinkSelfContainedDefault::True => "true",
+            LinkSelfContainedDefault::Musl => "musl",
+            LinkSelfContainedDefault::Mingw => "mingw",
         }
         .to_json()
     }
diff --git a/compiler/rustc_target/src/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs
index 207a87ab039..61553e71b45 100644
--- a/compiler/rustc_target/src/spec/linux_musl_base.rs
+++ b/compiler/rustc_target/src/spec/linux_musl_base.rs
@@ -1,13 +1,13 @@
-use crate::spec::crt_objects::{self, CrtObjectsFallback};
+use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
 use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
 
     base.env = "musl".into();
-    base.pre_link_objects_fallback = crt_objects::pre_musl_fallback();
-    base.post_link_objects_fallback = crt_objects::post_musl_fallback();
-    base.crt_objects_fallback = Some(CrtObjectsFallback::Musl);
+    base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained();
+    base.post_link_objects_self_contained = crt_objects::post_musl_self_contained();
+    base.link_self_contained = LinkSelfContainedDefault::Musl;
 
     // These targets statically link libc by default
     base.crt_static_default = true;
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f7abeafd38f..0b49edc232c 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -37,7 +37,7 @@
 use crate::abi::Endian;
 use crate::json::{Json, ToJson};
 use crate::spec::abi::{lookup as lookup_abi, Abi};
-use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
+use crate::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::symbol::{sym, Symbol};
@@ -1172,13 +1172,10 @@ pub struct TargetOptions {
     /// Objects to link before and after all other object code.
     pub pre_link_objects: CrtObjects,
     pub post_link_objects: CrtObjects,
-    /// Same as `(pre|post)_link_objects`, but when we fail to pull the objects with help of the
-    /// target's native gcc and fall back to the "self-contained" mode and pull them manually.
-    /// See `crt_objects.rs` for some more detailed documentation.
-    pub pre_link_objects_fallback: CrtObjects,
-    pub post_link_objects_fallback: CrtObjects,
-    /// Which logic to use to determine whether to fall back to the "self-contained" mode or not.
-    pub crt_objects_fallback: Option<CrtObjectsFallback>,
+    /// Same as `(pre|post)_link_objects`, but when self-contained linking mode is enabled.
+    pub pre_link_objects_self_contained: CrtObjects,
+    pub post_link_objects_self_contained: CrtObjects,
+    pub link_self_contained: LinkSelfContainedDefault,
 
     /// Linker arguments that are unconditionally passed after any
     /// user-defined but before post-link objects. Standard platform
@@ -1554,9 +1551,9 @@ impl Default for TargetOptions {
             relro_level: RelroLevel::None,
             pre_link_objects: Default::default(),
             post_link_objects: Default::default(),
-            pre_link_objects_fallback: Default::default(),
-            post_link_objects_fallback: Default::default(),
-            crt_objects_fallback: None,
+            pre_link_objects_self_contained: Default::default(),
+            post_link_objects_self_contained: Default::default(),
+            link_self_contained: LinkSelfContainedDefault::False,
             late_link_args: LinkArgs::new(),
             late_link_args_dynamic: LinkArgs::new(),
             late_link_args_static: LinkArgs::new(),
@@ -1977,20 +1974,20 @@ impl Target {
                 Ok::<(), String>(())
             } );
 
-            ($key_name:ident, crt_objects_fallback) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
-                    match s.parse::<CrtObjectsFallback>() {
-                        Ok(fallback) => base.$key_name = Some(fallback),
-                        _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
-                                                      Use 'musl', 'mingw' or 'wasm'", s))),
+            ($key_name:ident = $json_name:expr, link_self_contained) => ( {
+                let name = $json_name;
+                obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
+                    match s.parse::<LinkSelfContainedDefault>() {
+                        Ok(lsc_default) => base.$key_name = lsc_default,
+                        _ => return Some(Err(format!("'{}' is not a valid `-Clink-self-contained` default. \
+                                                      Use 'false', 'true', 'musl' or 'mingw'", s))),
                     }
                     Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
-            ($key_name:ident, link_objects) => ( {
-                let name = (stringify!($key_name)).replace("_", "-");
-                if let Some(val) = obj.remove(&name) {
+            ($key_name:ident = $json_name:expr, link_objects) => ( {
+                let name = $json_name;
+                if let Some(val) = obj.remove(name) {
                     let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
                         JSON object with fields per CRT object kind.", name))?;
                     let mut args = CrtObjects::new();
@@ -2112,11 +2109,11 @@ impl Target {
         key!(linker_flavor, LinkerFlavor)?;
         key!(linker, optional);
         key!(lld_flavor, LldFlavor)?;
-        key!(pre_link_objects, link_objects);
-        key!(post_link_objects, link_objects);
-        key!(pre_link_objects_fallback, link_objects);
-        key!(post_link_objects_fallback, link_objects);
-        key!(crt_objects_fallback, crt_objects_fallback)?;
+        key!(pre_link_objects = "pre-link-objects", link_objects);
+        key!(post_link_objects = "post-link-objects", link_objects);
+        key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
+        key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
+        key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
         key!(pre_link_args, link_args);
         key!(late_link_args, link_args);
         key!(late_link_args_dynamic, link_args);
@@ -2357,9 +2354,9 @@ impl ToJson for Target {
         target_option_val!(lld_flavor);
         target_option_val!(pre_link_objects);
         target_option_val!(post_link_objects);
-        target_option_val!(pre_link_objects_fallback);
-        target_option_val!(post_link_objects_fallback);
-        target_option_val!(crt_objects_fallback);
+        target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
+        target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
+        target_option_val!(link_self_contained, "crt-objects-fallback");
         target_option_val!(link_args - pre_link_args);
         target_option_val!(link_args - late_link_args);
         target_option_val!(link_args - late_link_args_dynamic);
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index 1db6db78b17..03e579aee0a 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -110,9 +110,9 @@ impl Target {
         }
 
         assert!(
-            (self.pre_link_objects_fallback.is_empty()
-                && self.post_link_objects_fallback.is_empty())
-                || self.crt_objects_fallback.is_some()
+            (self.pre_link_objects_self_contained.is_empty()
+                && self.post_link_objects_self_contained.is_empty())
+                || self.link_self_contained != LinkSelfContainedDefault::False
         );
 
         // If your target really needs to deviate from the rules below,
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 280457d68b9..9c30487f4ab 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -82,8 +82,8 @@ pub fn target() -> Target {
     options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
     options.add_pre_link_args(LinkerFlavor::Gcc, &["--target=wasm32-wasi"]);
 
-    options.pre_link_objects_fallback = crt_objects::pre_wasi_fallback();
-    options.post_link_objects_fallback = crt_objects::post_wasi_fallback();
+    options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
+    options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
 
     // Right now this is a bit of a workaround but we're currently saying that
     // the target by default has a static crt which we're taking as a signal
diff --git a/compiler/rustc_target/src/spec/wasm_base.rs b/compiler/rustc_target/src/spec/wasm_base.rs
index 9216d3e7b65..28a07701eae 100644
--- a/compiler/rustc_target/src/spec/wasm_base.rs
+++ b/compiler/rustc_target/src/spec/wasm_base.rs
@@ -1,4 +1,4 @@
-use super::crt_objects::CrtObjectsFallback;
+use super::crt_objects::LinkSelfContainedDefault;
 use super::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel};
 
 pub fn options() -> TargetOptions {
@@ -96,7 +96,8 @@ pub fn options() -> TargetOptions {
 
         pre_link_args,
 
-        crt_objects_fallback: Some(CrtObjectsFallback::Wasm),
+        // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
+        link_self_contained: LinkSelfContainedDefault::True,
 
         // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
         // PIC code is implemented this has quite a drastic effect if it stays
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 90e0af3e38a..0107f7a52c6 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::crt_objects::{self, CrtObjectsFallback};
+use crate::spec::crt_objects::{self, LinkSelfContainedDefault};
 use crate::spec::{cvs, LinkerFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
@@ -76,9 +76,9 @@ pub fn opts() -> TargetOptions {
         pre_link_args,
         pre_link_objects: crt_objects::pre_mingw(),
         post_link_objects: crt_objects::post_mingw(),
-        pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
-        post_link_objects_fallback: crt_objects::post_mingw_fallback(),
-        crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
+        pre_link_objects_self_contained: crt_objects::pre_mingw_self_contained(),
+        post_link_objects_self_contained: crt_objects::post_mingw_self_contained(),
+        link_self_contained: LinkSelfContainedDefault::Mingw,
         late_link_args,
         late_link_args_dynamic,
         late_link_args_static,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8ab1aa65d3a..a54b36262b2 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -734,7 +734,21 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
         result
     }
 
-    // FIXME: Constants should participate in orphan checking.
+    /// All possible values for a constant parameter already exist
+    /// in the crate defining the trait, so they are always non-local[^1].
+    ///
+    /// Because there's no way to have an impl where the first local
+    /// generic argument is a constant, we also don't have to fail
+    /// the orphan check when encountering a parameter or a generic constant.
+    ///
+    /// This means that we can completely ignore constants during the orphan check.
+    ///
+    /// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
+    ///
+    /// [^1]: This might not hold for function pointers or trait objects in the future.
+    /// As these should be quite rare as const arguments and especially rare as impl
+    /// parameters, allowing uncovered const parameters in impls seems more useful
+    /// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
     fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         ControlFlow::CONTINUE
     }
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 3f2a0da8d65..05686be5d4b 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -69,6 +69,9 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
         // to note that it's safe to call, since
         // safe extern fns are otherwise unprecedented.
         sym::abort
+        | sym::assert_inhabited
+        | sym::assert_zero_valid
+        | sym::assert_uninit_valid
         | sym::size_of
         | sym::min_align_of
         | sym::needs_drop
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index f549807c39c..ebf1f506183 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -292,6 +292,17 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
         intravisit::walk_expr(self, e);
     }
 
+    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
+        match &p.kind {
+            hir::GenericParamKind::Lifetime { .. } => {
+                // Nothing to write back here
+            }
+            hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => {
+                self.tcx().sess.delay_span_bug(p.span, format!("unexpected generic param: {p:?}"));
+            }
+        }
+    }
+
     fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
         self.visit_node_id(b.span, b.hir_id);
         intravisit::walk_block(self, b);
diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs
new file mode 100644
index 00000000000..9b479a9f8ad
--- /dev/null
+++ b/library/core/src/iter/adapters/array_chunks.rs
@@ -0,0 +1,182 @@
+use crate::array;
+use crate::iter::{ByRefSized, FusedIterator, Iterator};
+use crate::ops::{ControlFlow, NeverShortCircuit, Try};
+
+/// An iterator over `N` elements of the iterator at a time.
+///
+/// The chunks do not overlap. If `N` does not divide the length of the
+/// iterator, then the last up to `N-1` elements will be omitted.
+///
+/// This `struct` is created by the [`array_chunks`][Iterator::array_chunks]
+/// method on [`Iterator`]. See its documentation for more.
+#[derive(Debug, Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub struct ArrayChunks<I: Iterator, const N: usize> {
+    iter: I,
+    remainder: Option<array::IntoIter<I::Item, N>>,
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+    I: Iterator,
+{
+    #[track_caller]
+    pub(in crate::iter) fn new(iter: I) -> Self {
+        assert!(N != 0, "chunk size must be non-zero");
+        Self { iter, remainder: None }
+    }
+
+    /// Returns an iterator over the remaining elements of the original iterator
+    /// that are not going to be returned by this iterator. The returned
+    /// iterator will yield at most `N-1` elements.
+    #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+    #[inline]
+    pub fn into_remainder(self) -> Option<array::IntoIter<I::Item, N>> {
+        self.remainder
+    }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> Iterator for ArrayChunks<I, N>
+where
+    I: Iterator,
+{
+    type Item = [I::Item; N];
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        self.try_for_each(ControlFlow::Break).break_value()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let (lower, upper) = self.iter.size_hint();
+
+        (lower / N, upper.map(|n| n / N))
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.iter.count() / N
+    }
+
+    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        let mut acc = init;
+        loop {
+            match self.iter.next_chunk() {
+                Ok(chunk) => acc = f(acc, chunk)?,
+                Err(remainder) => {
+                    // Make sure to not override `self.remainder` with an empty array
+                    // when `next` is called after `ArrayChunks` exhaustion.
+                    self.remainder.get_or_insert(remainder);
+
+                    break try { acc };
+                }
+            }
+        }
+    }
+
+    fn fold<B, F>(mut self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
+    }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
+where
+    I: DoubleEndedIterator + ExactSizeIterator,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.try_rfold((), |(), x| ControlFlow::Break(x)).break_value()
+    }
+
+    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        // We are iterating from the back we need to first handle the remainder.
+        self.next_back_remainder();
+
+        let mut acc = init;
+        let mut iter = ByRefSized(&mut self.iter).rev();
+
+        // NB remainder is handled by `next_back_remainder`, so
+        // `next_chunk` can't return `Err` with non-empty remainder
+        // (assuming correct `I as ExactSizeIterator` impl).
+        while let Ok(mut chunk) = iter.next_chunk() {
+            // FIXME: do not do double reverse
+            //        (we could instead add `next_chunk_back` for example)
+            chunk.reverse();
+            acc = f(acc, chunk)?
+        }
+
+        try { acc }
+    }
+
+    fn rfold<B, F>(mut self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        self.try_rfold(init, NeverShortCircuit::wrap_mut_2(f)).0
+    }
+}
+
+impl<I, const N: usize> ArrayChunks<I, N>
+where
+    I: DoubleEndedIterator + ExactSizeIterator,
+{
+    /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
+    fn next_back_remainder(&mut self) {
+        // Make sure to not override `self.remainder` with an empty array
+        // when `next_back` is called after `ArrayChunks` exhaustion.
+        if self.remainder.is_some() {
+            return;
+        }
+
+        // We use the `ExactSizeIterator` implementation of the underlying
+        // iterator to know how many remaining elements there are.
+        let rem = self.iter.len() % N;
+
+        // Take the last `rem` elements out of `self.iter`.
+        let mut remainder =
+            // SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
+            unsafe { self.iter.by_ref().rev().take(rem).next_chunk().unwrap_err_unchecked() };
+
+        // We used `.rev()` above, so we need to re-reverse the reminder
+        remainder.as_mut_slice().reverse();
+        self.remainder = Some(remainder);
+    }
+}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}
+
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
+where
+    I: ExactSizeIterator,
+{
+    #[inline]
+    fn len(&self) -> usize {
+        self.iter.len() / N
+    }
+
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.iter.len() < N
+    }
+}
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 916a26e2424..bf4fabad32a 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -1,6 +1,7 @@
 use crate::iter::{InPlaceIterable, Iterator};
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
 
+mod array_chunks;
 mod by_ref_sized;
 mod chain;
 mod cloned;
@@ -32,6 +33,9 @@ pub use self::{
     scan::Scan, skip::Skip, skip_while::SkipWhile, take::Take, take_while::TakeWhile, zip::Zip,
 };
 
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::array_chunks::ArrayChunks;
+
 #[unstable(feature = "std_internals", issue = "none")]
 pub use self::by_ref_sized::ByRefSized;
 
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index d5c6aed5b6c..9514466bd0c 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -398,6 +398,8 @@ pub use self::traits::{
 
 #[stable(feature = "iter_zip", since = "1.59.0")]
 pub use self::adapters::zip;
+#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+pub use self::adapters::ArrayChunks;
 #[unstable(feature = "std_internals", issue = "none")]
 pub use self::adapters::ByRefSized;
 #[stable(feature = "iter_cloned", since = "1.1.0")]
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 275412b57b5..b2d08f4b0f6 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -5,7 +5,7 @@ use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 use super::super::try_process;
 use super::super::ByRefSized;
 use super::super::TrustedRandomAccessNoCoerce;
-use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
+use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
 use super::super::{FlatMap, Flatten};
 use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
 use super::super::{
@@ -3316,6 +3316,49 @@ pub trait Iterator {
         Cycle::new(self)
     }
 
+    /// Returns an iterator over `N` elements of the iterator at a time.
+    ///
+    /// The chunks do not overlap. If `N` does not divide the length of the
+    /// iterator, then the last up to `N-1` elements will be omitted and can be
+    /// retrieved from the [`.into_remainder()`][ArrayChunks::into_remainder]
+    /// function of the iterator.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `N` is 0.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_array_chunks)]
+    ///
+    /// let mut iter = "lorem".chars().array_chunks();
+    /// assert_eq!(iter.next(), Some(['l', 'o']));
+    /// assert_eq!(iter.next(), Some(['r', 'e']));
+    /// assert_eq!(iter.next(), None);
+    /// assert_eq!(iter.into_remainder().unwrap().as_slice(), &['m']);
+    /// ```
+    ///
+    /// ```
+    /// #![feature(iter_array_chunks)]
+    ///
+    /// let data = [1, 1, 2, -2, 6, 0, 3, 1];
+    /// //          ^-----^  ^------^
+    /// for [x, y, z] in data.iter().array_chunks() {
+    ///     assert_eq!(x + y + z, 4);
+    /// }
+    /// ```
+    #[track_caller]
+    #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
+    fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
+    where
+        Self: Sized,
+    {
+        ArrayChunks::new(self)
+    }
+
     /// Sums the elements of an iterator.
     ///
     /// Takes each element, adds them together, and returns the result.
diff --git a/library/core/tests/iter/adapters/array_chunks.rs b/library/core/tests/iter/adapters/array_chunks.rs
new file mode 100644
index 00000000000..4e9d89e1e58
--- /dev/null
+++ b/library/core/tests/iter/adapters/array_chunks.rs
@@ -0,0 +1,179 @@
+use core::cell::Cell;
+use core::iter::{self, Iterator};
+
+use super::*;
+
+#[test]
+fn test_iterator_array_chunks_infer() {
+    let xs = [1, 1, 2, -2, 6, 0, 3, 1];
+    for [a, b, c] in xs.iter().copied().array_chunks() {
+        assert_eq!(a + b + c, 4);
+    }
+}
+
+#[test]
+fn test_iterator_array_chunks_clone_and_drop() {
+    let count = Cell::new(0);
+    let mut it = (0..5).map(|_| CountDrop::new(&count)).array_chunks::<3>();
+    assert_eq!(it.by_ref().count(), 1);
+    assert_eq!(count.get(), 3);
+    let mut it2 = it.clone();
+    assert_eq!(count.get(), 3);
+    assert_eq!(it.into_remainder().unwrap().len(), 2);
+    assert_eq!(count.get(), 5);
+    assert!(it2.next().is_none());
+    assert_eq!(it2.into_remainder().unwrap().len(), 2);
+    assert_eq!(count.get(), 7);
+}
+
+#[test]
+fn test_iterator_array_chunks_remainder() {
+    let mut it = (0..11).array_chunks::<4>();
+    assert_eq!(it.next(), Some([0, 1, 2, 3]));
+    assert_eq!(it.next(), Some([4, 5, 6, 7]));
+    assert_eq!(it.next(), None);
+    assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]);
+}
+
+#[test]
+fn test_iterator_array_chunks_size_hint() {
+    let it = (0..6).array_chunks::<1>();
+    assert_eq!(it.size_hint(), (6, Some(6)));
+
+    let it = (0..6).array_chunks::<3>();
+    assert_eq!(it.size_hint(), (2, Some(2)));
+
+    let it = (0..6).array_chunks::<5>();
+    assert_eq!(it.size_hint(), (1, Some(1)));
+
+    let it = (0..6).array_chunks::<7>();
+    assert_eq!(it.size_hint(), (0, Some(0)));
+
+    let it = (1..).array_chunks::<2>();
+    assert_eq!(it.size_hint(), (usize::MAX / 2, None));
+
+    let it = (1..).filter(|x| x % 2 != 0).array_chunks::<2>();
+    assert_eq!(it.size_hint(), (0, None));
+}
+
+#[test]
+fn test_iterator_array_chunks_count() {
+    let it = (0..6).array_chunks::<1>();
+    assert_eq!(it.count(), 6);
+
+    let it = (0..6).array_chunks::<3>();
+    assert_eq!(it.count(), 2);
+
+    let it = (0..6).array_chunks::<5>();
+    assert_eq!(it.count(), 1);
+
+    let it = (0..6).array_chunks::<7>();
+    assert_eq!(it.count(), 0);
+
+    let it = (0..6).filter(|x| x % 2 == 0).array_chunks::<2>();
+    assert_eq!(it.count(), 1);
+
+    let it = iter::empty::<i32>().array_chunks::<2>();
+    assert_eq!(it.count(), 0);
+
+    let it = [(); usize::MAX].iter().array_chunks::<2>();
+    assert_eq!(it.count(), usize::MAX / 2);
+}
+
+#[test]
+fn test_iterator_array_chunks_next_and_next_back() {
+    let mut it = (0..11).array_chunks::<3>();
+    assert_eq!(it.next(), Some([0, 1, 2]));
+    assert_eq!(it.next_back(), Some([6, 7, 8]));
+    assert_eq!(it.next(), Some([3, 4, 5]));
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.next_back(), None);
+    assert_eq!(it.next(), None);
+    assert_eq!(it.into_remainder().unwrap().as_slice(), &[9, 10]);
+}
+
+#[test]
+fn test_iterator_array_chunks_rev_remainder() {
+    let mut it = (0..11).array_chunks::<4>();
+    {
+        let mut it = it.by_ref().rev();
+        assert_eq!(it.next(), Some([4, 5, 6, 7]));
+        assert_eq!(it.next(), Some([0, 1, 2, 3]));
+        assert_eq!(it.next(), None);
+        assert_eq!(it.next(), None);
+    }
+    assert_eq!(it.into_remainder().unwrap().as_slice(), &[8, 9, 10]);
+}
+
+#[test]
+fn test_iterator_array_chunks_try_fold() {
+    let count = Cell::new(0);
+    let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
+    let result: Result<_, ()> = it.by_ref().try_fold(0, |acc, _item| Ok(acc + 1));
+    assert_eq!(result, Ok(3));
+    assert_eq!(count.get(), 9);
+    drop(it);
+    assert_eq!(count.get(), 10);
+
+    let count = Cell::new(0);
+    let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
+    let result = it.by_ref().try_fold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) });
+    assert_eq!(result, Err(2));
+    assert_eq!(count.get(), 9);
+    drop(it);
+    assert_eq!(count.get(), 9);
+}
+
+#[test]
+fn test_iterator_array_chunks_fold() {
+    let result = (1..11).array_chunks::<3>().fold(0, |acc, [a, b, c]| {
+        assert_eq!(acc + 1, a);
+        assert_eq!(acc + 2, b);
+        assert_eq!(acc + 3, c);
+        acc + 3
+    });
+    assert_eq!(result, 9);
+
+    let count = Cell::new(0);
+    let result =
+        (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1);
+    assert_eq!(result, 3);
+    assert_eq!(count.get(), 10);
+}
+
+#[test]
+fn test_iterator_array_chunks_try_rfold() {
+    let count = Cell::new(0);
+    let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
+    let result: Result<_, ()> = it.try_rfold(0, |acc, _item| Ok(acc + 1));
+    assert_eq!(result, Ok(3));
+    assert_eq!(count.get(), 9);
+    drop(it);
+    assert_eq!(count.get(), 10);
+
+    let count = Cell::new(0);
+    let mut it = (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>();
+    let result = it.try_rfold(0, |acc, _item| if acc < 2 { Ok(acc + 1) } else { Err(acc) });
+    assert_eq!(result, Err(2));
+    assert_eq!(count.get(), 9);
+    drop(it);
+    assert_eq!(count.get(), 10);
+}
+
+#[test]
+fn test_iterator_array_chunks_rfold() {
+    let result = (1..11).array_chunks::<3>().rfold(0, |acc, [a, b, c]| {
+        assert_eq!(10 - (acc + 1), c);
+        assert_eq!(10 - (acc + 2), b);
+        assert_eq!(10 - (acc + 3), a);
+        acc + 3
+    });
+    assert_eq!(result, 9);
+
+    let count = Cell::new(0);
+    let result =
+        (0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().rfold(0, |acc, _item| acc + 1);
+    assert_eq!(result, 3);
+    assert_eq!(count.get(), 10);
+}
diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs
index 567d9fe49ca..96539c0c394 100644
--- a/library/core/tests/iter/adapters/mod.rs
+++ b/library/core/tests/iter/adapters/mod.rs
@@ -1,3 +1,4 @@
+mod array_chunks;
 mod chain;
 mod cloned;
 mod copied;
@@ -183,3 +184,25 @@ impl Clone for CountClone {
         ret
     }
 }
+
+#[derive(Debug, Clone)]
+struct CountDrop<'a> {
+    dropped: bool,
+    count: &'a Cell<usize>,
+}
+
+impl<'a> CountDrop<'a> {
+    pub fn new(count: &'a Cell<usize>) -> Self {
+        Self { dropped: false, count }
+    }
+}
+
+impl Drop for CountDrop<'_> {
+    fn drop(&mut self) {
+        if self.dropped {
+            panic!("double drop");
+        }
+        self.dropped = true;
+        self.count.set(self.count.get() + 1);
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index df9b1073a09..09f1500f564 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -62,6 +62,7 @@
 #![feature(slice_partition_dedup)]
 #![feature(int_log)]
 #![feature(iter_advance_by)]
+#![feature(iter_array_chunks)]
 #![feature(iter_collect_into)]
 #![feature(iter_partition_in_place)]
 #![feature(iter_intersperse)]
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 1f2f9d97bdd..7778033eaa9 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -544,11 +544,11 @@ impl Default for FileTimes {
     fn default() -> Self {
         // Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return
         // an error in `set_times`.
-        // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+        // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
         // the same as for Redox.
-        #[cfg(any(target_os = "redox", target_os = "espidf"))]
+        #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: 0 };
-        #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
+        #[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ };
         Self([omit; 2])
     }
@@ -1083,9 +1083,9 @@ impl File {
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
         cfg_if::cfg_if! {
-            if #[cfg(any(target_os = "redox", target_os = "espidf"))] {
+            if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] {
                 // Redox doesn't appear to support `UTIME_OMIT`.
-                // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+                // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
                 // the same as for Redox.
                 drop(times);
                 Err(io::const_io_error!(
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 39d9ce1621b..1edb513f0b6 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -80,6 +80,7 @@ pub struct Flags {
     pub llvm_profile_generate: bool,
 }
 
+#[derive(Debug)]
 #[cfg_attr(test, derive(Clone))]
 pub enum Subcommand {
     Build {
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index a5a39a5a3cf..eb7da1bda73 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -11,7 +11,7 @@ use std::{
     io::{self, Write},
 };
 
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum Profile {
     Compiler,
     Codegen,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index addd6ffa11e..971617a8400 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -44,10 +44,6 @@ use utils::*;
 pub(crate) use self::types::*;
 pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
 
-pub(crate) trait Clean<'tcx, T> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
-}
-
 pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let mut items: Vec<Item> = vec![];
     let mut inserted = FxHashSet::default();
@@ -1925,7 +1921,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 }))
             }
             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
-                variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
+                variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
                 generics: clean_generics(generics, cx),
             }),
             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
@@ -1978,14 +1974,12 @@ fn clean_maybe_renamed_item<'tcx>(
     })
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::Variant<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let kind = VariantItem(clean_variant_data(&self.data, cx));
-        let what_rustc_thinks =
-            Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
-        // don't show `pub` for variants, which are always public
-        Item { visibility: Inherited, ..what_rustc_thinks }
-    }
+fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let kind = VariantItem(clean_variant_data(&variant.data, cx));
+    let what_rustc_thinks =
+        Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
+    // don't show `pub` for variants, which are always public
+    Item { visibility: Inherited, ..what_rustc_thinks }
 }
 
 fn clean_impl<'tcx>(
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 27ccff9a276..9d8ee52a3fa 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -111,6 +111,70 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
     write!(out, "<code>");
 }
 
+/// Write all the pending elements sharing a same (or at mergeable) `Class`.
+///
+/// If there is a "parent" (if a `EnterSpan` event was encountered) and the parent can be merged
+/// with the elements' class, then we simply write the elements since the `ExitSpan` event will
+/// close the tag.
+///
+/// Otherwise, if there is only one pending element, we let the `string` function handle both
+/// opening and closing the tag, otherwise we do it into this function.
+fn write_pending_elems(
+    out: &mut Buffer,
+    href_context: &Option<HrefContext<'_, '_, '_>>,
+    pending_elems: &mut Vec<(&str, Option<Class>)>,
+    current_class: &mut Option<Class>,
+    closing_tags: &[(&str, Class)],
+) {
+    if pending_elems.is_empty() {
+        return;
+    }
+    let mut done = false;
+    if let Some((_, parent_class)) = closing_tags.last() {
+        if can_merge(*current_class, Some(*parent_class), "") {
+            for (text, class) in pending_elems.iter() {
+                string(out, Escape(text), *class, &href_context, false);
+            }
+            done = true;
+        }
+    }
+    if !done {
+        // We only want to "open" the tag ourselves if we have more than one pending and if the current
+        // parent tag is not the same as our pending content.
+        let open_tag_ourselves = pending_elems.len() > 1;
+        let close_tag = if open_tag_ourselves {
+            enter_span(out, current_class.unwrap(), &href_context)
+        } else {
+            ""
+        };
+        for (text, class) in pending_elems.iter() {
+            string(out, Escape(text), *class, &href_context, !open_tag_ourselves);
+        }
+        if open_tag_ourselves {
+            exit_span(out, close_tag);
+        }
+    }
+    pending_elems.clear();
+    *current_class = None;
+}
+
+/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
+/// basically (since it's `Option<Class>`). The following rules apply:
+///
+/// * If two `Class` have the same variant, then they can be merged.
+/// * If the other `Class` is unclassified and only contains white characters (backline,
+///   whitespace, etc), it can be merged.
+/// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated
+///    CSS class).
+fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
+    match (class1, class2) {
+        (Some(c1), Some(c2)) => c1.is_equal_to(c2),
+        (Some(Class::Ident(_)), None) | (None, Some(Class::Ident(_))) => true,
+        (Some(_), None) | (None, Some(_)) => text.trim().is_empty(),
+        _ => false,
+    }
+}
+
 /// Convert the given `src` source code into HTML by adding classes for highlighting.
 ///
 /// This code is used to render code blocks (in the documentation) as well as the source code pages.
@@ -130,7 +194,15 @@ fn write_code(
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
-    let mut closing_tags: Vec<&'static str> = Vec::new();
+    // It contains the closing tag and the associated `Class`.
+    let mut closing_tags: Vec<(&'static str, Class)> = Vec::new();
+    // The following two variables are used to group HTML elements with same `class` attributes
+    // to reduce the DOM size.
+    let mut current_class: Option<Class> = None;
+    // We need to keep the `Class` for each element because it could contain a `Span` which is
+    // used to generate links.
+    let mut pending_elems: Vec<(&str, Option<Class>)> = Vec::new();
+
     Classifier::new(
         &src,
         href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
@@ -138,15 +210,48 @@ fn write_code(
     )
     .highlight(&mut |highlight| {
         match highlight {
-            Highlight::Token { text, class } => string(out, Escape(text), class, &href_context),
+            Highlight::Token { text, class } => {
+                // If the two `Class` are different, time to flush the current content and start
+                // a new one.
+                if !can_merge(current_class, class, text) {
+                    write_pending_elems(
+                        out,
+                        &href_context,
+                        &mut pending_elems,
+                        &mut current_class,
+                        &closing_tags,
+                    );
+                    current_class = class.map(Class::dummy);
+                } else if current_class.is_none() {
+                    current_class = class.map(Class::dummy);
+                }
+                pending_elems.push((text, class));
+            }
             Highlight::EnterSpan { class } => {
-                closing_tags.push(enter_span(out, class, &href_context))
+                // We flush everything just in case...
+                write_pending_elems(
+                    out,
+                    &href_context,
+                    &mut pending_elems,
+                    &mut current_class,
+                    &closing_tags,
+                );
+                closing_tags.push((enter_span(out, class, &href_context), class))
             }
             Highlight::ExitSpan => {
-                exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan"))
+                // We flush everything just in case...
+                write_pending_elems(
+                    out,
+                    &href_context,
+                    &mut pending_elems,
+                    &mut current_class,
+                    &closing_tags,
+                );
+                exit_span(out, closing_tags.pop().expect("ExitSpan without EnterSpan").0)
             }
         };
     });
+    write_pending_elems(out, &href_context, &mut pending_elems, &mut current_class, &closing_tags);
 }
 
 fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
@@ -160,7 +265,7 @@ enum Class {
     DocComment,
     Attribute,
     KeyWord,
-    // Keywords that do pointer/reference stuff.
+    /// Keywords that do pointer/reference stuff.
     RefKeyWord,
     Self_(Span),
     Macro(Span),
@@ -168,6 +273,7 @@ enum Class {
     String,
     Number,
     Bool,
+    /// `Ident` isn't rendered in the HTML but we still need it for the `Span` it contains.
     Ident(Span),
     Lifetime,
     PreludeTy,
@@ -177,6 +283,31 @@ enum Class {
 }
 
 impl Class {
+    /// It is only looking at the variant, not the variant content.
+    ///
+    /// It is used mostly to group multiple similar HTML elements into one `<span>` instead of
+    /// multiple ones.
+    fn is_equal_to(self, other: Self) -> bool {
+        match (self, other) {
+            (Self::Self_(_), Self::Self_(_))
+            | (Self::Macro(_), Self::Macro(_))
+            | (Self::Ident(_), Self::Ident(_))
+            | (Self::Decoration(_), Self::Decoration(_)) => true,
+            (x, y) => x == y,
+        }
+    }
+
+    /// If `self` contains a `Span`, it'll be replaced with `DUMMY_SP` to prevent creating links
+    /// on "empty content" (because of the attributes merge).
+    fn dummy(self) -> Self {
+        match self {
+            Self::Self_(_) => Self::Self_(DUMMY_SP),
+            Self::Macro(_) => Self::Macro(DUMMY_SP),
+            Self::Ident(_) => Self::Ident(DUMMY_SP),
+            s => s,
+        }
+    }
+
     /// Returns the css class expected by rustdoc for each `Class`.
     fn as_html(self) -> &'static str {
         match self {
@@ -191,7 +322,7 @@ impl Class {
             Class::String => "string",
             Class::Number => "number",
             Class::Bool => "bool-val",
-            Class::Ident(_) => "ident",
+            Class::Ident(_) => "",
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
@@ -630,7 +761,7 @@ impl<'a> Classifier<'a> {
             TokenKind::CloseBracket => {
                 if self.in_attribute {
                     self.in_attribute = false;
-                    sink(Highlight::Token { text: "]", class: None });
+                    sink(Highlight::Token { text: "]", class: Some(Class::Attribute) });
                     sink(Highlight::ExitSpan);
                     return;
                 }
@@ -701,7 +832,7 @@ fn enter_span(
     klass: Class,
     href_context: &Option<HrefContext<'_, '_, '_>>,
 ) -> &'static str {
-    string_without_closing_tag(out, "", Some(klass), href_context).expect(
+    string_without_closing_tag(out, "", Some(klass), href_context, true).expect(
         "internal error: enter_span was called with Some(klass) but did not return a \
             closing HTML tag",
     )
@@ -733,8 +864,10 @@ fn string<T: Display>(
     text: T,
     klass: Option<Class>,
     href_context: &Option<HrefContext<'_, '_, '_>>,
+    open_tag: bool,
 ) {
-    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context) {
+    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
+    {
         out.write_str(closing_tag);
     }
 }
@@ -753,6 +886,7 @@ fn string_without_closing_tag<T: Display>(
     text: T,
     klass: Option<Class>,
     href_context: &Option<HrefContext<'_, '_, '_>>,
+    open_tag: bool,
 ) -> Option<&'static str> {
     let Some(klass) = klass
     else {
@@ -761,6 +895,10 @@ fn string_without_closing_tag<T: Display>(
     };
     let Some(def_span) = klass.get_span()
     else {
+        if !open_tag {
+            write!(out, "{}", text);
+            return None;
+        }
         write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
         return Some("</span>");
     };
@@ -784,6 +922,7 @@ fn string_without_closing_tag<T: Display>(
             path
         });
     }
+
     if let Some(href_context) = href_context {
         if let Some(href) =
             href_context.context.shared.span_correspondance_map.get(&def_span).and_then(|href| {
@@ -812,12 +951,33 @@ fn string_without_closing_tag<T: Display>(
                 }
             })
         {
-            write!(out, "<a class=\"{}\" href=\"{}\">{}", klass.as_html(), href, text_s);
+            if !open_tag {
+                // We're already inside an element which has the same klass, no need to give it
+                // again.
+                write!(out, "<a href=\"{}\">{}", href, text_s);
+            } else {
+                let klass_s = klass.as_html();
+                if klass_s.is_empty() {
+                    write!(out, "<a href=\"{}\">{}", href, text_s);
+                } else {
+                    write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s);
+                }
+            }
             return Some("</a>");
         }
     }
-    write!(out, "<span class=\"{}\">{}", klass.as_html(), text_s);
-    Some("</span>")
+    if !open_tag {
+        write!(out, "{}", text_s);
+        return None;
+    }
+    let klass_s = klass.as_html();
+    if klass_s.is_empty() {
+        write!(out, "{}", text_s);
+        Some("")
+    } else {
+        write!(out, "<span class=\"{}\">{}", klass_s, text_s);
+        Some("</span>")
+    }
 }
 
 #[cfg(test)]
diff --git a/src/librustdoc/html/highlight/fixtures/decorations.html b/src/librustdoc/html/highlight/fixtures/decorations.html
index ae4dba116d6..21848978721 100644
--- a/src/librustdoc/html/highlight/fixtures/decorations.html
+++ b/src/librustdoc/html/highlight/fixtures/decorations.html
@@ -1,2 +1,2 @@
-<span class="example"><span class="kw">let</span> <span class="ident">x</span> = <span class="number">1</span>;</span>
-<span class="kw">let</span> <span class="ident">y</span> = <span class="number">2</span>;
\ No newline at end of file
+<span class="example"><span class="kw">let </span>x = <span class="number">1</span>;</span>
+<span class="kw">let </span>y = <span class="number">2</span>;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html
index 1c8dbffe78c..30b50ca7c66 100644
--- a/src/librustdoc/html/highlight/fixtures/dos_line.html
+++ b/src/librustdoc/html/highlight/fixtures/dos_line.html
@@ -1,3 +1,3 @@
-<span class="kw">pub</span> <span class="kw">fn</span> <span class="ident">foo</span>() {
+<span class="kw">pub fn </span>foo() {
 <span class="macro">println!</span>(<span class="string">&quot;foo&quot;</span>);
 }
diff --git a/src/librustdoc/html/highlight/fixtures/highlight.html b/src/librustdoc/html/highlight/fixtures/highlight.html
index 17f23278ec1..9f73e03f95e 100644
--- a/src/librustdoc/html/highlight/fixtures/highlight.html
+++ b/src/librustdoc/html/highlight/fixtures/highlight.html
@@ -1,4 +1,4 @@
-<span class="kw">use</span> <span class="ident"><span class="kw">crate</span>::a::foo</span>;
-<span class="kw">use</span> <span class="ident"><span class="self">self</span>::whatever</span>;
-<span class="kw">let</span> <span class="ident">x</span> = <span class="ident"><span class="kw">super</span>::b::foo</span>;
-<span class="kw">let</span> <span class="ident">y</span> = <span class="ident"><span class="self">Self</span>::whatever</span>;
\ No newline at end of file
+<span class="kw">use </span><span class="kw">crate</span>::a::foo;
+<span class="kw">use </span><span class="self">self</span>::whatever;
+<span class="kw">let </span>x = <span class="kw">super</span>::b::foo;
+<span class="kw">let </span>y = <span class="self">Self</span>::whatever;
\ No newline at end of file
diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html
index ea797fd99d3..ae2650528eb 100644
--- a/src/librustdoc/html/highlight/fixtures/sample.html
+++ b/src/librustdoc/html/highlight/fixtures/sample.html
@@ -8,30 +8,30 @@
 .lifetime { color: #B76514; }
 .question-mark { color: #ff9011; }
 </style>
-<pre><code><span class="attribute">#![<span class="ident">crate_type</span> = <span class="string">&quot;lib&quot;</span>]</span>
+<pre><code><span class="attribute">#![crate_type = <span class="string">&quot;lib&quot;</span>]</span>
 
-<span class="kw">use</span> <span class="ident">std::path</span>::{<span class="ident">Path</span>, <span class="ident">PathBuf</span>};
+<span class="kw">use </span>std::path::{Path, PathBuf};
 
-<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> = <span class="string">&quot;linux&quot;</span>)]</span>
-<span class="kw">fn</span> <span class="ident">main</span>() -&gt; () {
-    <span class="kw">let</span> <span class="ident">foo</span> = <span class="bool-val">true</span> &amp;&amp; <span class="bool-val">false</span> || <span class="bool-val">true</span>;
-    <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () = <span class="number">0</span>;
-    <span class="kw">let</span> <span class="kw">_</span> = <span class="kw-2">&amp;</span><span class="ident">foo</span>;
-    <span class="kw">let</span> <span class="kw">_</span> = &amp;&amp;<span class="ident">foo</span>;
-    <span class="kw">let</span> <span class="kw">_</span> = <span class="kw-2">*</span><span class="ident">foo</span>;
-    <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&amp;mut</span> <span class="ident">bar</span>);
-    <span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> &lt; <span class="ident">N</span> &amp;&amp; <span class="ident">index</span> &lt;= <span class="self">self</span>.<span class="ident">length</span>);
-    <span class="ident">::std::env::var</span>(<span class="string">&quot;gateau&quot;</span>).<span class="ident">is_ok</span>();
-    <span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
-    <span class="kw">let</span> <span class="ident">s</span>:<span class="ident">std::path::PathBuf</span> = <span class="ident">std::path::PathBuf::new</span>();
-    <span class="kw">let</span> <span class="kw-2">mut</span> <span class="ident">s</span> = <span class="ident">String::new</span>();
+<span class="attribute">#[cfg(target_os = <span class="string">&quot;linux&quot;</span>)]</span>
+<span class="kw">fn </span>main() -&gt; () {
+    <span class="kw">let </span>foo = <span class="bool-val">true </span>&amp;&amp; <span class="bool-val">false </span>|| <span class="bool-val">true</span>;
+    <span class="kw">let _</span>: <span class="kw-2">*const </span>() = <span class="number">0</span>;
+    <span class="kw">let _ </span>= <span class="kw-2">&amp;</span>foo;
+    <span class="kw">let _ </span>= &amp;&amp;foo;
+    <span class="kw">let _ </span>= <span class="kw-2">*</span>foo;
+    <span class="macro">mac!</span>(foo, <span class="kw-2">&amp;mut </span>bar);
+    <span class="macro">assert!</span>(<span class="self">self</span>.length &lt; N &amp;&amp; index &lt;= <span class="self">self</span>.length);
+    ::std::env::var(<span class="string">&quot;gateau&quot;</span>).is_ok();
+    <span class="attribute">#[rustfmt::skip]</span>
+    <span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new();
+    <span class="kw">let </span><span class="kw-2">mut </span>s = String::new();
 
-    <span class="kw">match</span> <span class="kw-2">&amp;</span><span class="ident">s</span> {
-        <span class="kw-2">ref</span> <span class="kw-2">mut</span> <span class="ident">x</span> =&gt; {}
+    <span class="kw">match </span><span class="kw-2">&amp;</span>s {
+        <span class="kw-2">ref mut </span>x =&gt; {}
     }
 }
 
-<span class="macro">macro_rules!</span> <span class="ident">bar</span> {
-    (<span class="macro-nonterminal">$</span><span class="macro-nonterminal">foo</span>:<span class="ident">tt</span>) =&gt; {};
+<span class="macro">macro_rules!</span> bar {
+    (<span class="macro-nonterminal">$foo</span>:tt) =&gt; {};
 }
 </code></pre>
diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html
index ac8bd28f6c3..9f891528264 100644
--- a/src/librustdoc/html/highlight/fixtures/union.html
+++ b/src/librustdoc/html/highlight/fixtures/union.html
@@ -1,8 +1,8 @@
-<span class="kw">union</span> <span class="ident">Foo</span> {
-    <span class="ident">i</span>: <span class="ident">i8</span>,
-    <span class="ident">u</span>: <span class="ident">i8</span>,
+<span class="kw">union </span>Foo {
+    i: i8,
+    u: i8,
 }
 
-<span class="kw">fn</span> <span class="ident">main</span>() {
-    <span class="kw">let</span> <span class="ident">union</span> = <span class="number">0</span>;
+<span class="kw">fn </span>main() {
+    <span class="kw">let </span>union = <span class="number">0</span>;
 }
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index b8218867a8b..4dfb64abbeb 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -250,9 +250,6 @@ pre.rust .self {
 pre.rust .attribute {
 	color: #e6e1cf;
 }
-pre.rust .attribute .ident {
-	color: #e6e1cf;
-}
 
 .example-wrap > pre.line-number {
 	color: #5c67736e;
@@ -398,8 +395,7 @@ pre.rust .comment {}
 .block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,
 .content .fnname {}
 pre.rust .kw {}
-pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,
-pre.rust .attribute .ident {}
+pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute {}
 .content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {}
 pre.rust .doccomment {}
 .stab.deprecated {}
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 6188e0ac0a9..39f83c99808 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -202,7 +202,7 @@ pre.rust .kw { color: #ab8ac1; }
 pre.rust .kw-2, pre.rust .prelude-ty { color: #769acb; }
 pre.rust .number, pre.rust .string { color: #83a300; }
 pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .attribute, pre.rust .attribute .ident { color: #ee6868; }
+pre.rust .attribute { color: #ee6868; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
 pre.rust .lifetime { color: #d97f26; }
 pre.rust .question-mark {
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index fba790b6193..5698088c790 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -184,7 +184,7 @@ pre.rust .kw { color: #8959A8; }
 pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
 pre.rust .number, pre.rust .string { color: #718C00; }
 pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
-pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
+pre.rust .attribute { color: #C82829; }
 pre.rust .comment { color: #8E908C; }
 pre.rust .doccomment { color: #4D4D4C; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
diff --git a/src/test/rustdoc/issue-41783.codeblock.html b/src/test/rustdoc/issue-41783.codeblock.html
new file mode 100644
index 00000000000..b919935e4b4
--- /dev/null
+++ b/src/test/rustdoc/issue-41783.codeblock.html
@@ -0,0 +1,5 @@
+<code># single
+## double
+### triple
+<span class="attribute">#[outer]</span>
+<span class="attribute">#![inner]</span></code>
\ No newline at end of file
diff --git a/src/test/rustdoc/issue-41783.rs b/src/test/rustdoc/issue-41783.rs
index 58a55a73815..d6771602879 100644
--- a/src/test/rustdoc/issue-41783.rs
+++ b/src/test/rustdoc/issue-41783.rs
@@ -1,11 +1,9 @@
 // @has issue_41783/struct.Foo.html
 // @!hasraw - 'space'
 // @!hasraw - 'comment'
-// @hasraw - '# <span class="ident">single'
-// @hasraw - '## <span class="ident">double</span>'
-// @hasraw - '### <span class="ident">triple</span>'
-// @hasraw - '<span class="attribute">#[<span class="ident">outer</span>]</span>'
-// @hasraw - '<span class="attribute">#![<span class="ident">inner</span>]</span>'
+// @hasraw - '<span class="attribute">#[outer]</span>'
+// @hasraw - '<span class="attribute">#![inner]</span>'
+// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
 
 /// ```no_run
 /// # # space
diff --git a/src/test/rustdoc/macro_rules-matchers.rs b/src/test/rustdoc/macro_rules-matchers.rs
index 98026663e5a..96f4126c7c2 100644
--- a/src/test/rustdoc/macro_rules-matchers.rs
+++ b/src/test/rustdoc/macro_rules-matchers.rs
@@ -5,14 +5,12 @@
 
 // @has 'foo/macro.todo.html'
 // @has - '//span[@class="macro"]' 'macro_rules!'
-// @has - '//span[@class="ident"]' 'todo'
+// @hasraw - ' todo {'
 
 // @hasraw - '{ () =&gt; { ... }; ($('
 // @has - '//span[@class="macro-nonterminal"]' '$'
 // @has - '//span[@class="macro-nonterminal"]' 'arg'
-// @hasraw - ':'
-// @has - '//span[@class="ident"]' 'tt'
-// @hasraw - ')+'
+// @hasraw - ':tt)+'
 // @hasraw - ') =&gt; { ... }; }'
 pub use std::todo;
 
diff --git a/src/test/ui/closures/binder/disallow-const.rs b/src/test/ui/closures/binder/disallow-const.rs
new file mode 100644
index 00000000000..72ad6185d37
--- /dev/null
+++ b/src/test/ui/closures/binder/disallow-const.rs
@@ -0,0 +1,6 @@
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    for<const N: i32> || -> () {};
+    //~^ ERROR only lifetime parameters can be used in this context
+}
diff --git a/src/test/ui/closures/binder/disallow-const.stderr b/src/test/ui/closures/binder/disallow-const.stderr
new file mode 100644
index 00000000000..3c3b43d8cf3
--- /dev/null
+++ b/src/test/ui/closures/binder/disallow-const.stderr
@@ -0,0 +1,8 @@
+error: only lifetime parameters can be used in this context
+  --> $DIR/disallow-const.rs:4:15
+   |
+LL |     for<const N: i32> || -> () {};
+   |               ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/closures/binder/disallow-ty.rs b/src/test/ui/closures/binder/disallow-ty.rs
new file mode 100644
index 00000000000..bbe3d8488d9
--- /dev/null
+++ b/src/test/ui/closures/binder/disallow-ty.rs
@@ -0,0 +1,6 @@
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    for<T> || -> () {};
+    //~^ ERROR only lifetime parameters can be used in this context
+}
diff --git a/src/test/ui/closures/binder/disallow-ty.stderr b/src/test/ui/closures/binder/disallow-ty.stderr
new file mode 100644
index 00000000000..51b6773edea
--- /dev/null
+++ b/src/test/ui/closures/binder/disallow-ty.stderr
@@ -0,0 +1,8 @@
+error: only lifetime parameters can be used in this context
+  --> $DIR/disallow-ty.rs:4:9
+   |
+LL |     for<T> || -> () {};
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/coherence/auxiliary/trait-with-const-param.rs b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs
new file mode 100644
index 00000000000..a44eb14f8e4
--- /dev/null
+++ b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs
@@ -0,0 +1 @@
+pub trait Trait<const N: usize, T> {}
diff --git a/src/test/ui/coherence/const-generics-orphan-check-ok.rs b/src/test/ui/coherence/const-generics-orphan-check-ok.rs
new file mode 100644
index 00000000000..217e8aed234
--- /dev/null
+++ b/src/test/ui/coherence/const-generics-orphan-check-ok.rs
@@ -0,0 +1,28 @@
+// check-pass
+// aux-build:trait-with-const-param.rs
+extern crate trait_with_const_param;
+use trait_with_const_param::*;
+
+// Trivial case, const param after local type.
+struct Local1;
+impl<const N: usize, T> Trait<N, T> for Local1 {}
+
+// Concrete consts behave the same as foreign types,
+// so this also trivially works.
+impl Trait<3, Local1> for i32 {}
+
+// This case isn't as trivial as we would forbid type
+// parameters here, we do allow const parameters though.
+//
+// The reason that type parameters are forbidden for
+// `impl<T> Trait<T, LocalInA> for i32 {}` is that another
+// downstream crate can add `impl<T> Trait<LocalInB, T> for i32`.
+// As these two impls would overlap we forbid any impls which
+// have a type parameter in front of a local type.
+//
+// With const parameters this issue does not exist as there are no
+// constants local to another downstream crate.
+struct Local2;
+impl<const N: usize> Trait<N, Local2> for i32 {}
+
+fn main() {}
diff --git a/src/test/ui/consts/assert-type-intrinsics.rs b/src/test/ui/consts/assert-type-intrinsics.rs
index 38e5c454edf..3ce3e1bdbac 100644
--- a/src/test/ui/consts/assert-type-intrinsics.rs
+++ b/src/test/ui/consts/assert-type-intrinsics.rs
@@ -13,10 +13,10 @@ fn main() {
     const _BAD1: () = unsafe {
         MaybeUninit::<!>::uninit().assume_init();
     };
-    const _BAD2: () = unsafe {
+    const _BAD2: () = {
         intrinsics::assert_uninit_valid::<bool>();
     };
-    const _BAD3: () = unsafe {
+    const _BAD3: () = {
         intrinsics::assert_zero_valid::<&'static i32>();
     };
 }
diff --git a/src/test/ui/consts/assert-type-intrinsics.stderr b/src/test/ui/consts/assert-type-intrinsics.stderr
index f3b9170d428..6eab10197b8 100644
--- a/src/test/ui/consts/assert-type-intrinsics.stderr
+++ b/src/test/ui/consts/assert-type-intrinsics.stderr
@@ -13,7 +13,7 @@ LL |         MaybeUninit::<!>::uninit().assume_init();
 error: any use of this value will cause an error
   --> $DIR/assert-type-intrinsics.rs:17:9
    |
-LL |     const _BAD2: () = unsafe {
+LL |     const _BAD2: () = {
    |     ---------------
 LL |         intrinsics::assert_uninit_valid::<bool>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
@@ -24,7 +24,7 @@ LL |         intrinsics::assert_uninit_valid::<bool>();
 error: any use of this value will cause an error
   --> $DIR/assert-type-intrinsics.rs:20:9
    |
-LL |     const _BAD3: () = unsafe {
+LL |     const _BAD3: () = {
    |     ---------------
 LL |         intrinsics::assert_zero_valid::<&'static i32>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
@@ -51,7 +51,7 @@ Future breakage diagnostic:
 error: any use of this value will cause an error
   --> $DIR/assert-type-intrinsics.rs:17:9
    |
-LL |     const _BAD2: () = unsafe {
+LL |     const _BAD2: () = {
    |     ---------------
 LL |         intrinsics::assert_uninit_valid::<bool>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to leave type `bool` uninitialized, which is invalid
@@ -64,7 +64,7 @@ Future breakage diagnostic:
 error: any use of this value will cause an error
   --> $DIR/assert-type-intrinsics.rs:20:9
    |
-LL |     const _BAD3: () = unsafe {
+LL |     const _BAD3: () = {
    |     ---------------
 LL |         intrinsics::assert_zero_valid::<&'static i32>();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `&i32`, which is invalid
diff --git a/src/test/ui/parser/issue-100197-mut-let.fixed b/src/test/ui/parser/issue-100197-mut-let.fixed
new file mode 100644
index 00000000000..5a895622200
--- /dev/null
+++ b/src/test/ui/parser/issue-100197-mut-let.fixed
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    let mut _x = 123;
+    //~^ ERROR invalid variable declaration
+}
diff --git a/src/test/ui/parser/issue-100197-mut-let.rs b/src/test/ui/parser/issue-100197-mut-let.rs
new file mode 100644
index 00000000000..71103813a6e
--- /dev/null
+++ b/src/test/ui/parser/issue-100197-mut-let.rs
@@ -0,0 +1,6 @@
+// run-rustfix
+
+fn main() {
+    mut let _x = 123;
+    //~^ ERROR invalid variable declaration
+}
diff --git a/src/test/ui/parser/issue-100197-mut-let.stderr b/src/test/ui/parser/issue-100197-mut-let.stderr
new file mode 100644
index 00000000000..86658e4f39f
--- /dev/null
+++ b/src/test/ui/parser/issue-100197-mut-let.stderr
@@ -0,0 +1,8 @@
+error: invalid variable declaration
+  --> $DIR/issue-100197-mut-let.rs:4:5
+   |
+LL |     mut let _x = 123;
+   |     ^^^^^^^ help: switch the order of `mut` and `let`: `let mut`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.fixed b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.fixed
new file mode 100644
index 00000000000..64ab6f62b77
--- /dev/null
+++ b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+
+fn main() {
+    const _FOO: i32 = 123;
+    //~^ ERROR const` and `let` are mutually exclusive
+    const _BAR: i32 = 123;
+    //~^ ERROR `const` and `let` are mutually exclusive
+}
diff --git a/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.rs b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.rs
new file mode 100644
index 00000000000..50520971ffb
--- /dev/null
+++ b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+
+fn main() {
+    const let _FOO: i32 = 123;
+    //~^ ERROR const` and `let` are mutually exclusive
+    let const _BAR: i32 = 123;
+    //~^ ERROR `const` and `let` are mutually exclusive
+}
diff --git a/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.stderr b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.stderr
new file mode 100644
index 00000000000..72377fc379c
--- /dev/null
+++ b/src/test/ui/parser/issue-99910-const-let-mutually-exclusive.stderr
@@ -0,0 +1,14 @@
+error: `const` and `let` are mutually exclusive
+  --> $DIR/issue-99910-const-let-mutually-exclusive.rs:4:5
+   |
+LL |     const let _FOO: i32 = 123;
+   |     ^^^^^^^^^ help: remove `let`: `const`
+
+error: `const` and `let` are mutually exclusive
+  --> $DIR/issue-99910-const-let-mutually-exclusive.rs:6:5
+   |
+LL |     let const _BAR: i32 = 123;
+   |     ^^^^^^^^^ help: remove `let`: `const`
+
+error: aborting due to 2 previous errors
+