diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dcdaa06caa2..2d8980fcd1a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -42,24 +42,20 @@ jobs:
       TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'pull_request'"
-    continue-on-error: "${{ matrix.tidy }}"
+    continue-on-error: "${{ matrix.name == 'mingw-check-tidy' }}"
     strategy:
       matrix:
         include:
           - name: mingw-check
-            tidy: false
             os: ubuntu-20.04-16core-64gb
             env: {}
           - name: mingw-check-tidy
-            tidy: true
             os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-llvm-14
-            tidy: false
             os: ubuntu-20.04-16core-64gb
             env: {}
           - name: x86_64-gnu-tools
-            tidy: false
             os: ubuntu-20.04-16core-64gb
             env: {}
     timeout-minutes: 600
@@ -98,9 +94,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -170,6 +163,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
     strategy:
@@ -521,9 +515,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -593,6 +584,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
     strategy:
@@ -637,9 +629,6 @@ jobs:
       - name: show the current environment
         run: src/ci/scripts/dump-environment.sh
         if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         if: success() && !env.SKIP_JOB
@@ -706,6 +695,7 @@ jobs:
       TOOLSTATE_PUBLISH: 1
       CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
       ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+      AWS_REGION: us-west-1
       CACHE_DOMAIN: ci-caches.rust-lang.org
     if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
     steps:
diff --git a/Cargo.lock b/Cargo.lock
index 6ef933bc409..724587a4a71 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -577,7 +577,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
 
 [[package]]
 name = "clippy"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "clap 4.2.1",
  "clippy_lints",
@@ -619,7 +619,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "arrayvec",
  "cargo_metadata 0.15.3",
@@ -643,7 +643,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -969,7 +969,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
 name = "declare_clippy_lint"
-version = "0.1.70"
+version = "0.1.71"
 dependencies = [
  "itertools",
  "quote",
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index b4597d5bc78..3d97d9b4895 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -729,42 +729,73 @@ pub trait LayoutCalculator {
             align = align.max(AbiAndPrefAlign::new(repr_align));
         }
 
-        let optimize = !repr.inhibit_union_abi_opt();
+        // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
+        // disabled, we can use that common ABI for the union as a whole.
+        struct AbiMismatch;
+        let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() {
+            // Can't optimize
+            Err(AbiMismatch)
+        } else {
+            Ok(None)
+        };
+
         let mut size = Size::ZERO;
-        let mut abi = Abi::Aggregate { sized: true };
         let only_variant = &variants[FIRST_VARIANT];
         for field in only_variant {
             assert!(field.0.is_sized());
+
             align = align.max(field.align());
+            size = cmp::max(size, field.size());
 
-            // If all non-ZST fields have the same ABI, forward this ABI
-            if optimize && !field.0.is_zst() {
-                // Discard valid range information and allow undef
-                let field_abi = match field.abi() {
-                    Abi::Scalar(x) => Abi::Scalar(x.to_union()),
-                    Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
-                    Abi::Vector { element: x, count } => {
-                        Abi::Vector { element: x.to_union(), count }
-                    }
-                    Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
-                };
-
-                if size == Size::ZERO {
-                    // first non ZST: initialize 'abi'
-                    abi = field_abi;
-                } else if abi != field_abi {
-                    // different fields have different ABI: reset to Aggregate
-                    abi = Abi::Aggregate { sized: true };
-                }
+            if field.0.is_zst() {
+                // Nothing more to do for ZST fields
+                continue;
             }
 
-            size = cmp::max(size, field.size());
+            if let Ok(common) = common_non_zst_abi_and_align {
+                // Discard valid range information and allow undef
+                let field_abi = field.abi().to_union();
+
+                if let Some((common_abi, common_align)) = common {
+                    if common_abi != field_abi {
+                        // Different fields have different ABI: disable opt
+                        common_non_zst_abi_and_align = Err(AbiMismatch);
+                    } else {
+                        // Fields with the same non-Aggregate ABI should also
+                        // have the same alignment
+                        if !matches!(common_abi, Abi::Aggregate { .. }) {
+                            assert_eq!(
+                                common_align,
+                                field.align().abi,
+                                "non-Aggregate field with matching ABI but differing alignment"
+                            );
+                        }
+                    }
+                } else {
+                    // First non-ZST field: record its ABI and alignment
+                    common_non_zst_abi_and_align = Ok(Some((field_abi, field.align().abi)));
+                }
+            }
         }
 
         if let Some(pack) = repr.pack {
             align = align.min(AbiAndPrefAlign::new(pack));
         }
 
+        // If all non-ZST fields have the same ABI, we may forward that ABI
+        // for the union as a whole, unless otherwise inhibited.
+        let abi = match common_non_zst_abi_and_align {
+            Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true },
+            Ok(Some((abi, _))) => {
+                if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
+                    // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
+                    Abi::Aggregate { sized: true }
+                } else {
+                    abi
+                }
+            }
+        };
+
         Some(LayoutS {
             variants: Variants::Single { index: FIRST_VARIANT },
             fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index d01a9b00304..43db66a3c28 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1272,6 +1272,50 @@ impl Abi {
     pub fn is_scalar(&self) -> bool {
         matches!(*self, Abi::Scalar(_))
     }
+
+    /// Returns the fixed alignment of this ABI, if any is mandated.
+    pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
+        Some(match *self {
+            Abi::Scalar(s) => s.align(cx),
+            Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
+            Abi::Vector { element, count } => {
+                cx.data_layout().vector_align(element.size(cx) * count)
+            }
+            Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+        })
+    }
+
+    /// Returns the fixed size of this ABI, if any is mandated.
+    pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
+        Some(match *self {
+            Abi::Scalar(s) => {
+                // No padding in scalars.
+                s.size(cx)
+            }
+            Abi::ScalarPair(s1, s2) => {
+                // May have some padding between the pair.
+                let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
+                (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
+            }
+            Abi::Vector { element, count } => {
+                // No padding in vectors, except possibly for trailing padding
+                // to make the size a multiple of align (e.g. for vectors of size 3).
+                (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
+            }
+            Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+        })
+    }
+
+    /// Discard validity range information and allow undef.
+    pub fn to_union(&self) -> Self {
+        assert!(self.is_sized());
+        match *self {
+            Abi::Scalar(s) => Abi::Scalar(s.to_union()),
+            Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
+            Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count },
+            Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
+        }
+    }
 }
 
 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index b5dba0713bf..e3ac8a8784a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1821,6 +1821,8 @@ pub enum LitKind {
     /// A byte string (`b"foo"`). Not stored as a symbol because it might be
     /// non-utf8, and symbols only allow utf8 strings.
     ByteStr(Lrc<[u8]>, StrStyle),
+    /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end.
+    CStr(Lrc<[u8]>, StrStyle),
     /// A byte char (`b'f'`).
     Byte(u8),
     /// A character literal (`'a'`).
@@ -1875,6 +1877,7 @@ impl LitKind {
             // unsuffixed variants
             LitKind::Str(..)
             | LitKind::ByteStr(..)
+            | LitKind::CStr(..)
             | LitKind::Byte(..)
             | LitKind::Char(..)
             | LitKind::Int(_, LitIntType::Unsuffixed)
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f947ae4d057..42b843482a3 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -74,6 +74,8 @@ pub enum LitKind {
     StrRaw(u8), // raw string delimited by `n` hash symbols
     ByteStr,
     ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -141,6 +143,10 @@ impl fmt::Display for Lit {
                 delim = "#".repeat(n as usize),
                 string = symbol
             )?,
+            CStr => write!(f, "c\"{symbol}\"")?,
+            CStrRaw(n) => {
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
+            }
             Integer | Float | Bool | Err => write!(f, "{symbol}")?,
         }
 
@@ -170,6 +176,7 @@ impl LitKind {
             Float => "float",
             Str | StrRaw(..) => "string",
             ByteStr | ByteStrRaw(..) => "byte string",
+            CStr | CStrRaw(..) => "C string",
             Err => "error",
         }
     }
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 74b842ac96e..15a54fe13d0 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,9 +2,13 @@
 
 use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
 use crate::token::{self, Token};
-use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
+use rustc_lexer::unescape::{
+    byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
+    Mode,
+};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use std::ops::Range;
 use std::{ascii, fmt, str};
 
 // Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -35,6 +39,7 @@ pub enum LitError {
     InvalidFloatSuffix,
     NonDecimalFloat(u32),
     IntTooLarge(u32),
+    NulInCStr(Range<usize>),
 }
 
 impl LitKind {
@@ -158,6 +163,52 @@ impl LitKind {
 
                 LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
             }
+            token::CStr => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Cooked)
+            }
+            token::CStrRaw(n) => {
+                let s = symbol.as_str();
+                let mut buf = Vec::with_capacity(s.len());
+                let mut error = Ok(());
+                unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
+                    Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+                        error = Err(LitError::NulInCStr(span));
+                    }
+                    Ok(CStrUnit::Byte(b)) => buf.push(b),
+                    Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+                    Ok(CStrUnit::Char(c)) => {
+                        buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+                    }
+                    Err(err) => {
+                        if err.is_fatal() {
+                            error = Err(LitError::LexerError);
+                        }
+                    }
+                });
+                error?;
+                buf.push(0);
+                LitKind::CStr(buf.into(), StrStyle::Raw(n))
+            }
             token::Err => LitKind::Err,
         })
     }
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
                     string = symbol
                 )?;
             }
+            LitKind::CStr(ref bytes, StrStyle::Cooked) => {
+                write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?
+            }
+            LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
+                // This can only be valid UTF-8.
+                let symbol = str::from_utf8(bytes).unwrap();
+                write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
+            }
             LitKind::Int(n, ty) => {
                 write!(f, "{n}")?;
                 match ty {
@@ -237,6 +296,8 @@ impl MetaItemLit {
             LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
             LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
             LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
+            LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
+            LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
             LitKind::Byte(_) => token::Byte,
             LitKind::Char(_) => token::Char,
             LitKind::Int(..) => token::Integer,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index a46fe9e898f..b960671bf6e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -572,6 +572,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
             }
         };
     }
+    gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
     gate_all!(
         if_let_guard,
         "`if let` guards are experimental",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ae346510ccc..3f80728a260 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -210,6 +210,10 @@ pub fn literal_to_string(lit: token::Lit) -> String {
         token::ByteStrRaw(n) => {
             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
         }
+        token::CStr => format!("c\"{symbol}\""),
+        token::CStrRaw(n) => {
+            format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
+        }
         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
     };
 
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index d2d3792345f..2a3092d3c7b 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -5,6 +5,7 @@ use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedM
 use rustc_ast_pretty::pprust;
 use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
 use rustc_macros::HashStable_Generic;
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::{feature_err, ParseSess};
@@ -581,32 +582,32 @@ pub fn cfg_matches(
 ) -> bool {
     eval_condition(cfg, sess, features, &mut |cfg| {
         try_gate_cfg(cfg.name, cfg.span, sess, features);
-        if let Some(names_valid) = &sess.check_config.names_valid {
-            if !names_valid.contains(&cfg.name) {
+        match sess.check_config.expecteds.get(&cfg.name) {
+            Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
+                sess.buffer_lint_with_diagnostic(
+                    UNEXPECTED_CFGS,
+                    cfg.span,
+                    lint_node_id,
+                    "unexpected `cfg` condition value",
+                    BuiltinLintDiagnostics::UnexpectedCfgValue(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
+                );
+            }
+            None if sess.check_config.exhaustive_names => {
                 sess.buffer_lint_with_diagnostic(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
                     "unexpected `cfg` condition name",
-                    BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
+                    BuiltinLintDiagnostics::UnexpectedCfgName(
+                        (cfg.name, cfg.name_span),
+                        cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+                    ),
                 );
             }
-        }
-        if let Some(value) = cfg.value {
-            if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
-                if !values.contains(&value) {
-                    sess.buffer_lint_with_diagnostic(
-                        UNEXPECTED_CFGS,
-                        cfg.span,
-                        lint_node_id,
-                        "unexpected `cfg` condition value",
-                        BuiltinLintDiagnostics::UnexpectedCfg(
-                            (cfg.name, cfg.name_span),
-                            cfg.value_span.map(|vs| (value, vs)),
-                        ),
-                    );
-                }
-            }
+            _ => { /* not unexpected */ }
         }
         sess.config.contains(&(cfg.name, cfg.value))
     })
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index b92964d03e9..50e88ae2eee 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -32,6 +32,10 @@ pub fn expand_concat(
                 Ok(ast::LitKind::Bool(b)) => {
                     accumulator.push_str(&b.to_string());
                 }
+                Ok(ast::LitKind::CStr(..)) => {
+                    cx.span_err(e.span, "cannot concatenate a C string literal");
+                    has_errors = true;
+                }
                 Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
                     cx.emit_err(errors::ConcatBytestr { span: e.span });
                     has_errors = true;
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index ba639c0a9fe..5ef35af0a05 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -18,6 +18,11 @@ fn invalid_type_err(
     };
     let snippet = cx.sess.source_map().span_to_snippet(span).ok();
     match ast::LitKind::from_token_lit(token_lit) {
+        Ok(ast::LitKind::CStr(_, _)) => {
+            // FIXME(c_str_literals): should concatenation of C string literals
+            // include the null bytes in the end?
+            cx.span_err(span, "cannot concatenate C string literals");
+        }
         Ok(ast::LitKind::Char(_)) => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index b6d7484bcce..d77634741fb 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -24,7 +24,7 @@ codegen_llvm_error_writing_def_file =
     Error writing .DEF file: {$error}
 
 codegen_llvm_error_calling_dlltool =
-    Error calling dlltool: {$error}
+    Error calling dlltool '{$dlltool_path}': {$error}
 
 codegen_llvm_dlltool_fail_import_library =
     Dlltool could not create import library: {$stdout}
@@ -82,7 +82,7 @@ codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO
 codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
 codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
 
-codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name}: {$message}
+codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
 codegen_llvm_from_llvm_diag = {$message}
 
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index f9af103c9ad..70bcbf92f38 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -238,7 +238,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 InlineAsmArch::Hexagon => {}
                 InlineAsmArch::LoongArch64 => {}
                 InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
-                InlineAsmArch::S390x => {}
+                InlineAsmArch::S390x => {
+                    constraints.push("~{cc}".to_string());
+                }
                 InlineAsmArch::SpirV => {}
                 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
                 InlineAsmArch::Bpf => {}
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 12da21dc477..a6416e9540c 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -198,7 +198,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 "arm" => ("arm", "--32"),
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
-            let result = std::process::Command::new(dlltool)
+            let result = std::process::Command::new(&dlltool)
                 .args([
                     "-d",
                     def_file_path.to_str().unwrap(),
@@ -218,9 +218,13 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 
             match result {
                 Err(e) => {
-                    sess.emit_fatal(ErrorCallingDllTool { error: e });
+                    sess.emit_fatal(ErrorCallingDllTool {
+                        dlltool_path: dlltool.to_string_lossy(),
+                        error: e,
+                    });
                 }
-                Ok(output) if !output.status.success() => {
+                // dlltool returns '0' on failure, so check for error output instead.
+                Ok(output) if !output.stderr.is_empty() => {
                     sess.emit_fatal(DlltoolFailImportLibrary {
                         stdout: String::from_utf8_lossy(&output.stdout),
                         stderr: String::from_utf8_lossy(&output.stderr),
@@ -431,7 +435,7 @@ fn string_to_io_error(s: String) -> io::Error {
 
 fn find_binutils_dlltool(sess: &Session) -> OsString {
     assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
-    if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool {
+    if let Some(dlltool_path) = &sess.opts.cg.dlltool {
         return dlltool_path.clone().into_os_string();
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 7136f750f39..ca2eab28f87 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -31,6 +31,7 @@ use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
 use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
 
+use crate::llvm::diagnostic::OptimizationDiagnosticKind;
 use libc::{c_char, c_int, c_uint, c_void, size_t};
 use std::ffi::CString;
 use std::fs;
@@ -363,6 +364,15 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
                     line: opt.line,
                     column: opt.column,
                     pass_name: &opt.pass_name,
+                    kind: match opt.kind {
+                        OptimizationDiagnosticKind::OptimizationRemark => "success",
+                        OptimizationDiagnosticKind::OptimizationMissed
+                        | OptimizationDiagnosticKind::OptimizationFailure => "missed",
+                        OptimizationDiagnosticKind::OptimizationAnalysis
+                        | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute
+                        | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis",
+                        OptimizationDiagnosticKind::OptimizationRemarkOther => "other",
+                    },
                     message: &opt.message,
                 });
             }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 2e9f89f4196..b138b0c0e70 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -322,7 +322,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let tcx = self.tcx;
 
         let def_id = instance.def_id();
-        let containing_scope = get_containing_scope(self, instance);
+        let (containing_scope, is_method) = get_containing_scope(self, instance);
         let span = tcx.def_span(def_id);
         let loc = self.lookup_debug_loc(span.lo());
         let file_metadata = file_metadata(self, &loc.file);
@@ -378,8 +378,29 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             }
         }
 
-        unsafe {
-            return llvm::LLVMRustDIBuilderCreateFunction(
+        // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
+        // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
+        // When we use this `decl` below, the subprogram definition gets created at the CU level
+        // with a DW_AT_specification pointing back to the type's declaration.
+        let decl = is_method.then(|| unsafe {
+            llvm::LLVMRustDIBuilderCreateMethod(
+                DIB(self),
+                containing_scope,
+                name.as_ptr().cast(),
+                name.len(),
+                linkage_name.as_ptr().cast(),
+                linkage_name.len(),
+                file_metadata,
+                loc.line,
+                function_type_metadata,
+                flags,
+                spflags & !DISPFlags::SPFlagDefinition,
+                template_parameters,
+            )
+        });
+
+        return unsafe {
+            llvm::LLVMRustDIBuilderCreateFunction(
                 DIB(self),
                 containing_scope,
                 name.as_ptr().cast(),
@@ -394,9 +415,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 spflags,
                 maybe_definition_llfn,
                 template_parameters,
-                None,
-            );
-        }
+                decl,
+            )
+        };
 
         fn get_function_signature<'ll, 'tcx>(
             cx: &CodegenCx<'ll, 'tcx>,
@@ -493,14 +514,16 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             names
         }
 
+        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
+        /// otherwise `false` for plain namespace scopes.
         fn get_containing_scope<'ll, 'tcx>(
             cx: &CodegenCx<'ll, 'tcx>,
             instance: Instance<'tcx>,
-        ) -> &'ll DIScope {
+        ) -> (&'ll DIScope, bool) {
             // First, let's see if this is a method within an inherent impl. Because
             // if yes, we want to make the result subroutine DIE a child of the
             // subroutine's self-type.
-            let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
+            if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
                 // If the method does *not* belong to a trait, proceed
                 if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
                     let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
@@ -511,39 +534,33 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
                     // Only "class" methods are generally understood by LLVM,
                     // so avoid methods on other types (e.g., `<*mut T>::null`).
-                    match impl_self_ty.kind() {
-                        ty::Adt(def, ..) if !def.is_box() => {
-                            // Again, only create type information if full debuginfo is enabled
-                            if cx.sess().opts.debuginfo == DebugInfo::Full
-                                && !impl_self_ty.has_param()
-                            {
-                                Some(type_di_node(cx, impl_self_ty))
-                            } else {
-                                Some(namespace::item_namespace(cx, def.did()))
-                            }
+                    if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() {
+                        // Again, only create type information if full debuginfo is enabled
+                        if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
+                        {
+                            return (type_di_node(cx, impl_self_ty), true);
+                        } else {
+                            return (namespace::item_namespace(cx, def.did()), false);
                         }
-                        _ => None,
                     }
                 } else {
                     // For trait method impls we still use the "parallel namespace"
                     // strategy
-                    None
                 }
-            });
+            }
 
-            self_type.unwrap_or_else(|| {
-                namespace::item_namespace(
-                    cx,
-                    DefId {
-                        krate: instance.def_id().krate,
-                        index: cx
-                            .tcx
-                            .def_key(instance.def_id())
-                            .parent
-                            .expect("get_containing_scope: missing parent?"),
-                    },
-                )
-            })
+            let scope = namespace::item_namespace(
+                cx,
+                DefId {
+                    krate: instance.def_id().krate,
+                    index: cx
+                        .tcx
+                        .def_key(instance.def_id())
+                        .parent
+                        .expect("get_containing_scope: missing parent?"),
+                },
+            );
+            (scope, false)
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index bae88d94293..6a9173ab450 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -67,7 +67,8 @@ pub(crate) struct ErrorWritingDEFFile {
 
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool {
+pub(crate) struct ErrorCallingDllTool<'a> {
+    pub dlltool_path: Cow<'a, str>,
     pub error: std::io::Error,
 }
 
@@ -195,6 +196,7 @@ pub(crate) struct FromLlvmOptimizationDiag<'a> {
     pub line: std::ffi::c_uint,
     pub column: std::ffi::c_uint,
     pub pass_name: &'a str,
+    pub kind: &'a str,
     pub message: &'a str,
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index c95148013eb..61365e6dc4b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1987,6 +1987,21 @@ extern "C" {
         Decl: Option<&'a DIDescriptor>,
     ) -> &'a DISubprogram;
 
+    pub fn LLVMRustDIBuilderCreateMethod<'a>(
+        Builder: &DIBuilder<'a>,
+        Scope: &'a DIDescriptor,
+        Name: *const c_char,
+        NameLen: size_t,
+        LinkageName: *const c_char,
+        LinkageNameLen: size_t,
+        File: &'a DIFile,
+        LineNo: c_uint,
+        Ty: &'a DIType,
+        Flags: DIFlags,
+        SPFlags: DISPFlags,
+        TParam: &'a DIArray,
+    ) -> &'a DISubprogram;
+
     pub fn LLVMRustDIBuilderCreateBasicType<'a>(
         Builder: &DIBuilder<'a>,
         Name: *const c_char,
@@ -2249,7 +2264,7 @@ extern "C" {
 
     pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
 
-    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
+    pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char);
     pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
     pub fn LLVMRustGetTargetFeature(
         T: &TargetMachine,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 46692fd5e8b..2fbdab9f8ce 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -329,7 +329,14 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
     require_inited();
     let tm = create_informational_target_machine(sess);
     match req {
-        PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
+        PrintRequest::TargetCPUs => {
+            // SAFETY generate a C compatible string from a byte slice to pass
+            // the target CPU name into LLVM, the lifetime of the reference is
+            // at least as long as the C function
+            let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
+                .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
+            unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) };
+        }
         PrintRequest::TargetFeatures => print_target_features(sess, tm),
         _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
     }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c42d59bd51c..c323372bda4 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1821,9 +1821,15 @@ impl SharedEmitterMain {
                         let source = sess
                             .source_map()
                             .new_source_file(FileName::inline_asm_source_code(&buffer), buffer);
-                        let source_span = Span::with_root_ctxt(source.start_pos, source.end_pos);
-                        let spans: Vec<_> =
-                            spans.iter().map(|sp| source_span.from_inner(*sp)).collect();
+                        let spans: Vec<_> = spans
+                            .iter()
+                            .map(|sp| {
+                                Span::with_root_ctxt(
+                                    source.normalized_byte_pos(sp.start as u32),
+                                    source.normalized_byte_pos(sp.end as u32),
+                                )
+                            })
+                            .collect();
                         err.span_note(spans, "instantiated into assembly here");
                     }
 
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 5cc87d1e56c..8dae5dab429 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -592,15 +592,6 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
-    if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
-        feature_err(
-            &tcx.sess.parse_sess,
-            sym::raw_dylib,
-            attr.span,
-            "`#[link_ordinal]` is unstable on x86",
-        )
-        .emit();
-    }
     let meta_item_list = attr.meta_item_list();
     let meta_item_list = meta_item_list.as_deref();
     let sole_meta_list = match meta_item_list {
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index b37797fef4c..9efbb34b515 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -2,6 +2,7 @@ use super::place::PlaceRef;
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
+use crate::common::TypeKind;
 use crate::glue;
 use crate::traits::*;
 use crate::MemFlags;
@@ -236,19 +237,47 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
         };
 
         match (&mut val, field.abi) {
-            (OperandValue::Immediate(llval), _) => {
+            (
+                OperandValue::Immediate(llval),
+                Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. },
+            ) => {
                 // Bools in union fields needs to be truncated.
                 *llval = bx.to_immediate(*llval, field);
                 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-                *llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field));
+                let ty = bx.cx().immediate_backend_type(field);
+                if bx.type_kind(ty) == TypeKind::Pointer {
+                    *llval = bx.pointercast(*llval, ty);
+                }
             }
             (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
                 // Bools in union fields needs to be truncated.
                 *a = bx.to_immediate_scalar(*a, a_abi);
                 *b = bx.to_immediate_scalar(*b, b_abi);
                 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-                *a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true));
-                *b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true));
+                let a_ty = bx.cx().scalar_pair_element_backend_type(field, 0, true);
+                let b_ty = bx.cx().scalar_pair_element_backend_type(field, 1, true);
+                if bx.type_kind(a_ty) == TypeKind::Pointer {
+                    *a = bx.pointercast(*a, a_ty);
+                }
+                if bx.type_kind(b_ty) == TypeKind::Pointer {
+                    *b = bx.pointercast(*b, b_ty);
+                }
+            }
+            // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
+            (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
+                assert!(matches!(self.layout.abi, Abi::Vector { .. }));
+
+                let llty = bx.cx().backend_type(self.layout);
+                let llfield_ty = bx.cx().backend_type(field);
+
+                // Can't bitcast an aggregate, so round trip through memory.
+                let lltemp = bx.alloca(llfield_ty, field.align.abi);
+                let llptr = bx.pointercast(lltemp, bx.cx().type_ptr_to(llty));
+                bx.store(*llval, llptr, field.align.abi);
+                *llval = bx.load(llfield_ty, lltemp, field.align.abi);
+            }
+            (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => {
+                bug!()
             }
             (OperandValue::Pair(..), _) => bug!(),
             (OperandValue::Ref(..), _) => bug!(),
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 5fac485de64..405f3d5b66d 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -25,7 +25,7 @@ use rustc_data_structures::profiling::{
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{
-    DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl,
+    DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl,
 };
 use rustc_feature::find_gated_cfg;
 use rustc_fluent_macro::fluent_messages;
@@ -55,7 +55,7 @@ use std::panic::{self, catch_unwind};
 use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
-use std::sync::LazyLock;
+use std::sync::OnceLock;
 use std::time::Instant;
 
 // This import blocks the use of panicking `print` and `println` in all the code
@@ -119,7 +119,7 @@ pub const EXIT_SUCCESS: i32 = 0;
 /// Exit status code used for compilation failures and invalid flags.
 pub const EXIT_FAILURE: i32 = 1;
 
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
 
 const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
@@ -1178,6 +1178,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
 pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
     catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
         if value.is::<rustc_errors::FatalErrorMarker>() {
+            #[allow(deprecated)]
             ErrorGuaranteed::unchecked_claim_error_was_emitted()
         } else {
             panic::resume_unwind(value);
@@ -1195,35 +1196,58 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
     }
 }
 
-static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    LazyLock::new(|| {
-        let hook = panic::take_hook();
-        panic::set_hook(Box::new(|info| {
-            // If the error was caused by a broken pipe then this is not a bug.
-            // Write the error and return immediately. See #98700.
-            #[cfg(windows)]
-            if let Some(msg) = info.payload().downcast_ref::<String>() {
-                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
-                {
-                    early_error_no_abort(ErrorOutputType::default(), &msg);
-                    return;
-                }
-            };
+/// Stores the default panic hook, from before [`install_ice_hook`] was called.
+static DEFAULT_HOOK: OnceLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+    OnceLock::new();
 
-            // Invoke the default handler, which prints the actual panic message and optionally a backtrace
-            // Don't do this for delayed bugs, which already emit their own more useful backtrace.
-            if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
-                (*DEFAULT_HOOK)(info);
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// The hook is intended to be useable even by external tools. You can pass a custom
+/// `bug_report_url`, or report arbitrary info in `extra_info`. Note that `extra_info` is called in
+/// a context where *the thread is currently panicking*, so it must not panic or the process will
+/// abort.
+///
+/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
+/// extra_info.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
+    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
+    // full backtraces. When a compiler ICE happens, we want to gather
+    // as much information as possible to present in the issue opened
+    // by the user. Compiler developers and other rustc users can
+    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+    // (e.g. `RUST_BACKTRACE=1`)
+    if std::env::var("RUST_BACKTRACE").is_err() {
+        std::env::set_var("RUST_BACKTRACE", "full");
+    }
 
-                // Separate the output with an empty line
-                eprintln!();
+    let default_hook = DEFAULT_HOOK.get_or_init(panic::take_hook);
+
+    panic::set_hook(Box::new(move |info| {
+        // If the error was caused by a broken pipe then this is not a bug.
+        // Write the error and return immediately. See #98700.
+        #[cfg(windows)]
+        if let Some(msg) = info.payload().downcast_ref::<String>() {
+            if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
+                early_error_no_abort(ErrorOutputType::default(), &msg);
+                return;
             }
+        };
 
-            // Print the ICE message
-            report_ice(info, BUG_REPORT_URL);
-        }));
-        hook
-    });
+        // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+        // Don't do this for delayed bugs, which already emit their own more useful backtrace.
+        if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
+            (*default_hook)(info);
+
+            // Separate the output with an empty line
+            eprintln!();
+        }
+
+        // Print the ICE message
+        report_ice(info, bug_report_url, extra_info);
+    }));
+}
 
 /// Prints the ICE message, including query stack, but without backtrace.
 ///
@@ -1231,7 +1255,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
 ///
 /// When `install_ice_hook` is called, this function will be called as the panic
 /// hook.
-pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
     let fallback_bundle =
         rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
     let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
@@ -1276,6 +1300,10 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 
     interface::try_print_query_stack(&handler, num_frames);
 
+    // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
+    // printed all the relevant info.
+    extra_info(&handler);
+
     #[cfg(windows)]
     if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
         // Trigger a debugger if we crashed during bootstrap
@@ -1283,22 +1311,6 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     }
 }
 
-/// Installs a panic hook that will print the ICE message on unexpected panics.
-///
-/// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook() {
-    // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
-    // full backtraces. When a compiler ICE happens, we want to gather
-    // as much information as possible to present in the issue opened
-    // by the user. Compiler developers and other rustc users can
-    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
-    // (e.g. `RUST_BACKTRACE=1`)
-    if std::env::var("RUST_BACKTRACE").is_err() {
-        std::env::set_var("RUST_BACKTRACE", "full");
-    }
-    LazyLock::force(&DEFAULT_HOOK);
-}
-
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
@@ -1369,7 +1381,7 @@ pub fn main() -> ! {
     init_rustc_env_logger();
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
-    install_ice_hook();
+    install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
     let exit_code = catch_with_exit_code(|| {
         let args = env::args_os()
             .enumerate()
diff --git a/compiler/rustc_error_codes/src/error_codes/E0726.md b/compiler/rustc_error_codes/src/error_codes/E0726.md
index e3794327f2d..a721e746ecd 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0726.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0726.md
@@ -25,8 +25,8 @@ block_on(future);
 
 Specify desired lifetime of parameter `content` or indicate the anonymous
 lifetime like `content: Content<'_>`. The anonymous lifetime tells the Rust
-compiler that `content` is only needed until create function is done with
-it's execution.
+compiler that `content` is only needed until the `create` function is done with
+its execution.
 
 The `implicit elision` meaning the omission of suggested lifetime that is
 `pub async fn create<'a>(content: Content<'a>) {}` is not allowed here as
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 1f1398342b1..ef528d87cb2 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -192,6 +192,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
                      became non-error ({:?}), after original `.emit()`",
                     db.inner.diagnostic.level,
                 );
+                #[allow(deprecated)]
                 ErrorGuaranteed::unchecked_claim_error_was_emitted()
             }
         }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f9c062d3a21..fcbd9a53b48 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1069,26 +1069,29 @@ impl Handler {
     }
 
     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
-        self.inner.borrow().has_errors().then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
 
     pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .has_errors_or_lint_errors()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors_or_lint_errors().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
     pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .has_errors_or_delayed_span_bugs()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().has_errors_or_delayed_span_bugs().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
     pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
-        self.inner
-            .borrow()
-            .is_compilation_going_to_fail()
-            .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+        self.inner.borrow().is_compilation_going_to_fail().then(|| {
+            #[allow(deprecated)]
+            ErrorGuaranteed::unchecked_claim_error_was_emitted()
+        })
     }
 
     pub fn print_error_count(&self, registry: &Registry) {
@@ -1333,6 +1336,7 @@ impl HandlerInner {
                 .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
 
             if !self.flags.report_delayed_bugs {
+                #[allow(deprecated)]
                 return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
             }
         }
@@ -1411,7 +1415,10 @@ impl HandlerInner {
                     self.bump_err_count();
                 }
 
-                guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+                #[allow(deprecated)]
+                {
+                    guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+                }
             } else {
                 self.bump_warn_count();
             }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 1e7d07bc22d..891e84a2f30 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -61,6 +61,8 @@ impl FromInternal<token::LitKind> for LitKind {
             token::StrRaw(n) => LitKind::StrRaw(n),
             token::ByteStr => LitKind::ByteStr,
             token::ByteStrRaw(n) => LitKind::ByteStrRaw(n),
+            token::CStr => LitKind::CStr,
+            token::CStrRaw(n) => LitKind::CStrRaw(n),
             token::Err => LitKind::Err,
             token::Bool => unreachable!(),
         }
@@ -78,6 +80,8 @@ impl ToInternal<token::LitKind> for LitKind {
             LitKind::StrRaw(n) => token::StrRaw(n),
             LitKind::ByteStr => token::ByteStr,
             LitKind::ByteStrRaw(n) => token::ByteStrRaw(n),
+            LitKind::CStr => token::CStr,
+            LitKind::CStrRaw(n) => token::CStrRaw(n),
             LitKind::Err => token::Err,
         }
     }
@@ -436,6 +440,8 @@ impl server::FreeFunctions for Rustc<'_, '_> {
                 | token::LitKind::StrRaw(_)
                 | token::LitKind::ByteStr
                 | token::LitKind::ByteStrRaw(_)
+                | token::LitKind::CStr
+                | token::LitKind::CStrRaw(_)
                 | token::LitKind::Err => return Err(()),
                 token::LitKind::Integer | token::LitKind::Float => {}
             }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 70d608a5ea4..5b2e4d15dfe 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -280,6 +280,8 @@ declare_features! (
     (accepted, pub_restricted, "1.18.0", Some(32409), None),
     /// Allows use of the postfix `?` operator in expressions.
     (accepted, question_mark, "1.13.0", Some(31436), None),
+    /// Allows the use of raw-dylibs (RFC 2627).
+    (accepted, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None),
     /// Allows keywords to be escaped for use as identifiers.
     (accepted, raw_identifiers, "1.30.0", Some(48589), None),
     /// Allows relaxing the coherence rules such that
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index dc5dc4608a0..27d30c315af 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -313,6 +313,8 @@ declare_features! (
     (active, async_closure, "1.37.0", Some(62290), None),
     /// Allows async functions to be declared, implemented, and used in traits.
     (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+    /// Allows `c"foo"` literals.
+    (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None),
     /// Treat `extern "C"` function as nounwind.
     (active, c_unwind, "1.52.0", Some(74990), None),
     /// Allows using C-variadics.
@@ -487,8 +489,6 @@ declare_features! (
     (active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
     /// Allows macro attributes on expressions, statements and non-inline modules.
     (active, proc_macro_hygiene, "1.30.0", Some(54727), None),
-    /// Allows the use of raw-dylibs (RFC 2627).
-    (active, raw_dylib, "1.65.0", Some(58713), None),
     /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
     (active, raw_ref_op, "1.41.0", Some(64490), None),
     /// Allows using the `#[register_tool]` attribute.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 0a8bd1d6123..1f08befb180 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -333,6 +333,7 @@ language_item_table! {
     RangeTo,                 sym::RangeTo,             range_to_struct,            Target::Struct,         GenericRequirement::None;
 
     String,                  sym::String,              string,                     Target::Struct,         GenericRequirement::None;
+    CStr,                    sym::CStr,                c_str,                      Target::Struct,         GenericRequirement::None;
 }
 
 pub enum GenericRequirement {
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index eaa75bde6c6..3b42b0fe246 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -192,7 +192,11 @@ hir_analysis_return_type_notation_equality_bound =
     return type notation is not allowed to use type equality
 
 hir_analysis_return_type_notation_missing_method =
-    cannot find associated function `{$assoc_name}` in trait `{$trait_name}`
+    cannot find associated function `{$assoc_name}` for `{$ty_name}`
+
+hir_analysis_return_type_notation_conflicting_bound =
+    ambiguous associated function `{$assoc_name}` for `{$ty_name}`
+    .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
 
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index c199b9da6fe..5ee0cf94360 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -1062,7 +1062,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
     /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
     /// named `assoc_name` into ty::Bounds. Ignore the rest.
-    pub(crate) fn compute_bounds_that_match_assoc_type(
+    pub(crate) fn compute_bounds_that_match_assoc_item(
         &self,
         param_ty: Ty<'tcx>,
         ast_bounds: &[hir::GenericBound<'_>],
@@ -1073,7 +1073,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         for ast_bound in ast_bounds {
             if let Some(trait_ref) = ast_bound.trait_ref()
                 && let Some(trait_did) = trait_ref.trait_def_id()
-                && self.tcx().trait_may_define_assoc_type(trait_did, assoc_name)
+                && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
             {
                 result.push(ast_bound.clone());
             }
@@ -1141,11 +1141,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ) {
                 trait_ref
             } else {
-                return Err(tcx.sess.emit_err(crate::errors::ReturnTypeNotationMissingMethod {
-                    span: binding.span,
-                    trait_name: tcx.item_name(trait_ref.def_id()),
-                    assoc_name: binding.item_name.name,
-                }));
+                self.one_bound_for_assoc_method(
+                    traits::supertraits(tcx, trait_ref),
+                    trait_ref.print_only_trait_path(),
+                    binding.item_name,
+                    path_span,
+                )?
             }
         } else if self.trait_defines_associated_item_named(
             trait_ref.def_id(),
@@ -1946,7 +1947,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let param_name = tcx.hir().ty_param_name(ty_param_def_id);
         self.one_bound_for_assoc_type(
             || {
-                traits::transitive_bounds_that_define_assoc_type(
+                traits::transitive_bounds_that_define_assoc_item(
                     tcx,
                     predicates.iter().filter_map(|(p, _)| {
                         Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
@@ -2081,6 +2082,46 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         Ok(bound)
     }
 
+    #[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
+    fn one_bound_for_assoc_method(
+        &self,
+        all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+        ty_name: impl Display,
+        assoc_name: Ident,
+        span: Span,
+    ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
+        let mut matching_candidates = all_candidates.filter(|r| {
+            self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
+        });
+
+        let candidate = match matching_candidates.next() {
+            Some(candidate) => candidate,
+            None => {
+                return Err(self.tcx().sess.emit_err(
+                    crate::errors::ReturnTypeNotationMissingMethod {
+                        span,
+                        ty_name: ty_name.to_string(),
+                        assoc_name: assoc_name.name,
+                    },
+                ));
+            }
+        };
+
+        if let Some(conflicting_candidate) = matching_candidates.next() {
+            return Err(self.tcx().sess.emit_err(
+                crate::errors::ReturnTypeNotationConflictingBound {
+                    span,
+                    ty_name: ty_name.to_string(),
+                    assoc_name: assoc_name.name,
+                    first_bound: candidate.print_only_trait_path(),
+                    second_bound: conflicting_candidate.print_only_trait_path(),
+                },
+            ));
+        }
+
+        Ok(candidate)
+    }
+
     // Create a type from a path to an associated type or to an enum variant.
     // For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
     // and item_segment is the path segment for `D`. We return a type and a def for
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index bae80807f71..5ba1ca1c807 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,12 +1,14 @@
 // FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
 //
 // We don't do any drop checking during hir typeck.
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::IgnoreRegions;
-use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_trait_selection::traits::{self, ObligationCtxt};
 
 use crate::errors;
 use crate::hir::def_id::{DefId, LocalDefId};
@@ -43,21 +45,20 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
         }
     }
     let dtor_self_type = tcx.type_of(drop_impl_did).subst_identity();
-    let dtor_predicates = tcx.predicates_of(drop_impl_did);
     match dtor_self_type.kind() {
-        ty::Adt(adt_def, self_to_impl_substs) => {
+        ty::Adt(adt_def, adt_to_impl_substs) => {
             ensure_drop_params_and_item_params_correspond(
                 tcx,
                 drop_impl_did.expect_local(),
                 adt_def.did(),
-                self_to_impl_substs,
+                adt_to_impl_substs,
             )?;
 
             ensure_drop_predicates_are_implied_by_item_defn(
                 tcx,
-                dtor_predicates,
+                drop_impl_did.expect_local(),
                 adt_def.did().expect_local(),
-                self_to_impl_substs,
+                adt_to_impl_substs,
             )
         }
         _ => {
@@ -78,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     tcx: TyCtxt<'tcx>,
     drop_impl_did: LocalDefId,
     self_type_did: DefId,
-    drop_impl_substs: SubstsRef<'tcx>,
+    adt_to_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let Err(arg) = tcx.uses_unique_generic_params(drop_impl_substs, IgnoreRegions::No) else {
+    let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else {
         return Ok(())
     };
 
@@ -111,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
 /// implied by assuming the predicates attached to self_type_did.
 fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     tcx: TyCtxt<'tcx>,
-    dtor_predicates: ty::GenericPredicates<'tcx>,
-    self_type_did: LocalDefId,
-    self_to_impl_substs: SubstsRef<'tcx>,
+    drop_impl_def_id: LocalDefId,
+    adt_def_id: LocalDefId,
+    adt_to_impl_substs: SubstsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let mut result = Ok(());
+    let infcx = tcx.infer_ctxt().build();
+    let ocx = ObligationCtxt::new(&infcx);
 
-    // Here is an example, analogous to that from
-    // `compare_impl_method`.
+    // Take the param-env of the adt and substitute the substs that show up in
+    // the implementation's self type. This gives us the assumptions that the
+    // self ty of the implementation is allowed to know just from it being a
+    // well-formed adt, since that's all we're allowed to assume while proving
+    // the Drop implementation is not specialized.
     //
-    // Consider a struct type:
-    //
-    //     struct Type<'c, 'b:'c, 'a> {
-    //         x: &'a Contents            // (contents are irrelevant;
-    //         y: &'c Cell<&'b Contents>, //  only the bounds matter for our purposes.)
-    //     }
-    //
-    // and a Drop impl:
-    //
-    //     impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
-    //         fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
-    //     }
-    //
-    // We start out with self_to_impl_substs, that maps the generic
-    // parameters of Type to that of the Drop impl.
-    //
-    //     self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
-    //
-    // Applying this to the predicates (i.e., assumptions) provided by the item
-    // definition yields the instantiated assumptions:
-    //
-    //     ['y : 'z]
-    //
-    // We then check all of the predicates of the Drop impl:
-    //
-    //     ['y:'z, 'x:'y]
-    //
-    // and ensure each is in the list of instantiated
-    // assumptions. Here, `'y:'z` is present, but `'x:'y` is
-    // absent. So we report an error that the Drop impl injected a
-    // predicate that is not present on the struct definition.
+    // We don't need to normalize this param-env or anything, since we're only
+    // substituting it with free params, so no additional param-env normalization
+    // can occur on top of what has been done in the param_env query itself.
+    let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id))
+        .subst(tcx, adt_to_impl_substs)
+        .with_constness(tcx.constness(drop_impl_def_id));
 
-    // We can assume the predicates attached to struct/enum definition
-    // hold.
-    let generic_assumptions = tcx.predicates_of(self_type_did);
+    for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
+        let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
+        let pred = ocx.normalize(&normalize_cause, param_env, pred);
+        let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl);
+        ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
+    }
 
-    let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
-    let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
+    // All of the custom error reporting logic is to preserve parity with the old
+    // error messages.
+    //
+    // They can probably get removed with better treatment of the new `DropImpl`
+    // obligation cause code, and perhaps some custom logic in `report_region_errors`.
 
-    debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates);
-
-    let self_param_env = tcx.param_env(self_type_did);
-
-    // An earlier version of this code attempted to do this checking
-    // via the traits::fulfill machinery. However, it ran into trouble
-    // since the fulfill machinery merely turns outlives-predicates
-    // 'a:'b and T:'b into region inference constraints. It is simpler
-    // just to look for all the predicates directly.
-
-    assert_eq!(dtor_predicates.parent, None);
-    for &(predicate, predicate_sp) in dtor_predicates.predicates {
-        // (We do not need to worry about deep analysis of type
-        // expressions etc because the Drop impls are already forced
-        // to take on a structure that is roughly an alpha-renaming of
-        // the generic parameters of the item definition.)
-
-        // This path now just checks *all* predicates via an instantiation of
-        // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
-        // after taking care of anonymizing late bound regions.
-        //
-        // However, it may be more efficient in the future to batch
-        // the analysis together via the fulfill (see comment above regarding
-        // the usage of the fulfill machinery), rather than the
-        // repeated `.iter().any(..)` calls.
-
-        // This closure is a more robust way to check `Predicate` equality
-        // than simple `==` checks (which were the previous implementation).
-        // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
-        // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
-        // while delegating on simple equality for the other `Predicate`.
-        // This implementation solves (Issue #59497) and (Issue #58311).
-        // It is unclear to me at the moment whether the approach based on `relate`
-        // could be extended easily also to the other `Predicate`.
-        let predicate_matches_closure = |p: Predicate<'tcx>| {
-            let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
-            let predicate = predicate.kind();
-            let p = p.kind();
-            match (predicate.skip_binder(), p.skip_binder()) {
-                (
-                    ty::PredicateKind::Clause(ty::Clause::Trait(a)),
-                    ty::PredicateKind::Clause(ty::Clause::Trait(b)),
-                ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::Clause(ty::Clause::Projection(a)),
-                    ty::PredicateKind::Clause(ty::Clause::Projection(b)),
-                ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::ConstEvaluatable(a),
-                    ty::PredicateKind::ConstEvaluatable(b),
-                ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
-                (
-                    ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                        ty_a,
-                        lt_a,
-                    ))),
-                    ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                        ty_b,
-                        lt_b,
-                    ))),
-                ) => {
-                    relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
-                        && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
-                }
-                (ty::PredicateKind::WellFormed(arg_a), ty::PredicateKind::WellFormed(arg_b)) => {
-                    relator.relate(predicate.rebind(arg_a), p.rebind(arg_b)).is_ok()
-                }
-                _ => predicate == p,
+    let errors = ocx.select_all_or_error();
+    if !errors.is_empty() {
+        let mut guar = None;
+        let mut root_predicates = FxHashSet::default();
+        for error in errors {
+            let root_predicate = error.root_obligation.predicate;
+            if root_predicates.insert(root_predicate) {
+                let item_span = tcx.def_span(adt_def_id);
+                let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+                guar = Some(
+                    struct_span_err!(
+                        tcx.sess,
+                        error.root_obligation.cause.span,
+                        E0367,
+                        "`Drop` impl requires `{root_predicate}` \
+                        but the {self_descr} it is implemented for does not",
+                    )
+                    .span_note(item_span, "the implementor must specify the same requirement")
+                    .emit(),
+                );
             }
-        };
-
-        if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) {
-            let item_span = tcx.def_span(self_type_did);
-            let self_descr = tcx.def_descr(self_type_did.to_def_id());
-            let reported = struct_span_err!(
-                tcx.sess,
-                predicate_sp,
-                E0367,
-                "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not",
-            )
-            .span_note(item_span, "the implementor must specify the same requirement")
-            .emit();
-            result = Err(reported);
         }
+        return Err(guar.unwrap());
     }
 
-    result
-}
-
-/// This is an implementation of the [`TypeRelation`] trait with the
-/// aim of simply comparing for equality (without side-effects).
-///
-/// It is not intended to be used anywhere else other than here.
-pub(crate) struct SimpleEqRelation<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx> SimpleEqRelation<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> SimpleEqRelation<'tcx> {
-        SimpleEqRelation { tcx, param_env }
-    }
-}
-
-impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn tag(&self) -> &'static str {
-        "dropck::SimpleEqRelation"
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        _: ty::Variance,
-        _info: ty::VarianceDiagInfo<'tcx>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        // Here we ignore variance because we require drop impl's types
-        // to be *exactly* the same as to the ones in the struct definition.
-        self.relate(a, b)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        debug!("SimpleEqRelation::tys(a={:?}, b={:?})", a, b);
-        ty::relate::super_relate_tys(self, a, b)
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        debug!("SimpleEqRelation::regions(a={:?}, b={:?})", a, b);
-
-        // We can just equate the regions because LBRs have been
-        // already anonymized.
-        if a == b {
-            Ok(a)
-        } else {
-            // I'm not sure is this `TypeError` is the right one, but
-            // it should not matter as it won't be checked (the dropck
-            // will emit its own, more informative and higher-level errors
-            // in case anything goes wrong).
-            Err(TypeError::RegionsPlaceholderMismatch)
+    let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
+    if !errors.is_empty() {
+        let mut guar = None;
+        for error in errors {
+            let item_span = tcx.def_span(adt_def_id);
+            let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+            let outlives = match error {
+                RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
+                RegionResolutionError::GenericBoundFailure(_, generic, r) => {
+                    format!("{generic}: {r}")
+                }
+                RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
+                RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
+                    format!("{b}: {a}", a = tcx.mk_re_var(a))
+                }
+            };
+            guar = Some(
+                struct_span_err!(
+                    tcx.sess,
+                    error.origin().span(),
+                    E0367,
+                    "`Drop` impl requires `{outlives}` \
+                    but the {self_descr} it is implemented for does not",
+                )
+                .span_note(item_span, "the implementor must specify the same requirement")
+                .emit(),
+            );
         }
+        return Err(guar.unwrap());
     }
 
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b);
-        ty::relate::super_relate_consts(self, a, b)
-    }
-
-    fn binders<T>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
-    where
-        T: Relate<'tcx>,
-    {
-        debug!("SimpleEqRelation::binders({:?}: {:?}", a, b);
-
-        // Anonymizing the LBRs is necessary to solve (Issue #59497).
-        // After we do so, it should be totally fine to skip the binders.
-        let anon_a = self.tcx.anonymize_bound_vars(a);
-        let anon_b = self.tcx.anonymize_bound_vars(b);
-        self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
-
-        Ok(a)
-    }
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 41547dd2a75..b65817ee95e 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -64,8 +64,8 @@ pub fn provide(providers: &mut Providers) {
         explicit_predicates_of: predicates_of::explicit_predicates_of,
         super_predicates_of: predicates_of::super_predicates_of,
         implied_predicates_of: predicates_of::implied_predicates_of,
-        super_predicates_that_define_assoc_type:
-            predicates_of::super_predicates_that_define_assoc_type,
+        super_predicates_that_define_assoc_item:
+            predicates_of::super_predicates_that_define_assoc_item,
         trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
         type_param_predicates: predicates_of::type_param_predicates,
         trait_def,
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 83470342a76..6c06957d1ee 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -565,7 +565,7 @@ pub(super) fn super_predicates_of(
     implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
 }
 
-pub(super) fn super_predicates_that_define_assoc_type(
+pub(super) fn super_predicates_that_define_assoc_item(
     tcx: TyCtxt<'_>,
     (trait_def_id, assoc_name): (DefId, Ident),
 ) -> ty::GenericPredicates<'_> {
@@ -640,7 +640,7 @@ pub(super) fn implied_predicates_with_filter(
         ),
         PredicateFilter::SelfThatDefines(assoc_name) => (
             // Convert the bounds that follow the colon (or equal) that reference the associated name
-            icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name),
+            icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
             // Include where clause bounds for `Self` that reference the associated name
             icx.type_parameter_bounds_in_generics(
                 generics,
@@ -819,7 +819,7 @@ impl<'tcx> ItemCtxt<'tcx> {
             hir::GenericBound::Trait(poly_trait_ref, _) => {
                 let trait_ref = &poly_trait_ref.trait_ref;
                 if let Some(trait_did) = trait_ref.trait_def_id() {
-                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+                    self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)
                 } else {
                     false
                 }
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 2e5d058c6ed..ab0dd01ce3a 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1652,17 +1652,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
                 let bound_vars = if let Some(type_def_id) = type_def_id
                     && self.tcx.def_kind(type_def_id) == DefKind::Trait
-                    // FIXME(return_type_notation): We could bound supertrait methods.
-                    && let Some(assoc_fn) = self
-                        .tcx
-                        .associated_items(type_def_id)
-                        .find_by_name_and_kind(self.tcx, binding.ident, ty::AssocKind::Fn, type_def_id)
+                    && let Some((mut bound_vars, assoc_fn)) =
+                        BoundVarContext::supertrait_hrtb_vars(
+                            self.tcx,
+                            type_def_id,
+                            binding.ident,
+                            ty::AssocKind::Fn,
+                        )
                 {
-                    self.tcx
-                        .generics_of(assoc_fn.def_id)
-                        .params
-                        .iter()
-                        .map(|param| match param.kind {
+                    bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
+                        |param| match param.kind {
                             ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
                                 ty::BoundRegionKind::BrNamed(param.def_id, param.name),
                             ),
@@ -1670,9 +1669,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                                 ty::BoundTyKind::Param(param.def_id, param.name),
                             ),
                             ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
-                        })
-                        .chain(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars())
-                        .collect()
+                        },
+                    ));
+                    bound_vars
+                        .extend(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars());
+                    bound_vars
                 } else {
                     self.tcx.sess.delay_span_bug(
                         binding.ident.span,
@@ -1689,8 +1690,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     });
                 });
             } else if let Some(type_def_id) = type_def_id {
-                let bound_vars =
-                    BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident);
+                let bound_vars = BoundVarContext::supertrait_hrtb_vars(
+                    self.tcx,
+                    type_def_id,
+                    binding.ident,
+                    ty::AssocKind::Type,
+                )
+                .map(|(bound_vars, _)| bound_vars);
                 self.with(scope, |this| {
                     let scope = Scope::Supertrait {
                         bound_vars: bound_vars.unwrap_or_default(),
@@ -1720,11 +1726,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
         def_id: DefId,
         assoc_name: Ident,
-    ) -> Option<Vec<ty::BoundVariableKind>> {
-        let trait_defines_associated_type_named = |trait_def_id: DefId| {
-            tcx.associated_items(trait_def_id)
-                .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id)
-                .is_some()
+        assoc_kind: ty::AssocKind,
+    ) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
+        let trait_defines_associated_item_named = |trait_def_id: DefId| {
+            tcx.associated_items(trait_def_id).find_by_name_and_kind(
+                tcx,
+                assoc_name,
+                assoc_kind,
+                trait_def_id,
+            )
         };
 
         use smallvec::{smallvec, SmallVec};
@@ -1742,10 +1752,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 _ => break None,
             }
 
-            if trait_defines_associated_type_named(def_id) {
-                break Some(bound_vars.into_iter().collect());
+            if let Some(assoc_item) = trait_defines_associated_item_named(def_id) {
+                break Some((bound_vars.into_iter().collect(), assoc_item));
             }
-            let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name));
+            let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name));
             let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index c0ee777722e..379a88538a9 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
     MultiSpan,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(Diagnostic)]
@@ -512,10 +512,22 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
 pub(crate) struct ReturnTypeNotationMissingMethod {
     #[primary_span]
     pub span: Span,
-    pub trait_name: Symbol,
+    pub ty_name: String,
     pub assoc_name: Symbol,
 }
 
+#[derive(Diagnostic)]
+#[diag(hir_analysis_return_type_notation_conflicting_bound)]
+#[note]
+pub(crate) struct ReturnTypeNotationConflictingBound<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub ty_name: String,
+    pub assoc_name: Symbol,
+    pub first_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    pub second_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
 pub(crate) struct PlaceholderNotAllowedItemSignatures {
@@ -657,7 +669,6 @@ pub enum ImplNotMarkedDefault {
     #[note]
     Err {
         #[primary_span]
-        #[label]
         span: Span,
         cname: Symbol,
         ident: Symbol,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index cbedbad1f38..9e78e6acba5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -854,9 +854,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let result = self
             .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
             .or_else(|error| {
+                let guar = self
+                    .tcx
+                    .sess
+                    .delay_span_bug(span, "method resolution should've emitted an error");
                 let result = match error {
                     method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
-                    _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+                    _ => Err(guar),
                 };
 
                 // If we have a path like `MyTrait::missing_method`, then don't register
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 78bd489a44b..4b8fc7303a2 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1300,6 +1300,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 opt_ty.unwrap_or_else(|| self.next_float_var())
             }
             ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+                tcx.lifetimes.re_static,
+                tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
+                    .skip_binder(),
+            ),
             ast::LitKind::Err => tcx.ty_error_misc(),
         }
     }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c9e13be02ff..2a51439b0a9 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -73,6 +73,8 @@ impl<'tcx> InferCtxt<'tcx> {
         R: ObligationEmittingRelation<'tcx>,
     {
         let a_is_expected = relation.a_is_expected();
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
 
         match (a.kind(), b.kind()) {
             // Relate integral variables to other types
@@ -163,6 +165,8 @@ impl<'tcx> InferCtxt<'tcx> {
         R: ObligationEmittingRelation<'tcx>,
     {
         debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
+        debug_assert!(!a.has_escaping_bound_vars());
+        debug_assert!(!b.has_escaping_bound_vars());
         if a == b {
             return Ok(a);
         }
@@ -238,22 +242,12 @@ impl<'tcx> InferCtxt<'tcx> {
             (_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
                 return self.unify_const_variable(vid, a);
             }
-            (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
-                // FIXME(#59490): Need to remove the leak check to accommodate
-                // escaping bound variables here.
-                if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.register_const_equate_obligation(a, b);
-                }
+            (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
+                if self.tcx.lazy_normalization() =>
+            {
+                relation.register_const_equate_obligation(a, b);
                 return Ok(b);
             }
-            (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => {
-                // FIXME(#59490): Need to remove the leak check to accommodate
-                // escaping bound variables here.
-                if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.register_const_equate_obligation(a, b);
-                }
-                return Ok(a);
-            }
             _ => {}
         }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index f1468cae455..8482ae2aa38 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -102,6 +102,17 @@ pub enum RegionResolutionError<'tcx> {
     ),
 }
 
+impl<'tcx> RegionResolutionError<'tcx> {
+    pub fn origin(&self) -> &SubregionOrigin<'tcx> {
+        match self {
+            RegionResolutionError::ConcreteFailure(origin, _, _)
+            | RegionResolutionError::GenericBoundFailure(origin, _, _)
+            | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
+            | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin,
+        }
+    }
+}
+
 struct RegionAndOrigin<'tcx> {
     region: Region<'tcx>,
     origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index f54e5e5e56f..74a78f38024 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -380,11 +380,11 @@ pub fn transitive_bounds<'tcx>(
 }
 
 /// A specialized variant of `elaborate` that only elaborates trait references that may
-/// define the given associated type `assoc_name`. It uses the
-/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
+/// define the given associated item with the name `assoc_name`. It uses the
+/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that
 /// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or
 /// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
-pub fn transitive_bounds_that_define_assoc_type<'tcx>(
+pub fn transitive_bounds_that_define_assoc_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
     assoc_name: Ident,
@@ -397,7 +397,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
             let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref);
             if visited.insert(anon_trait_ref) {
                 let super_predicates =
-                    tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name));
+                    tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name));
                 for (super_predicate, _) in super_predicates.predicates {
                     let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
                     if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 8e9150ba8ad..9d9f4ee13f4 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -9,11 +9,12 @@ use rustc_data_structures::OnDrop;
 use rustc_errors::registry::Registry;
 use rustc_errors::{ErrorGuaranteed, Handler};
 use rustc_lint::LintStore;
-use rustc_middle::ty;
+use rustc_middle::{bug, ty};
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
-use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{CheckCfg, ExpectedValues};
 use rustc_session::lint;
 use rustc_session::parse::{CrateConfig, ParseSess};
 use rustc_session::Session;
@@ -121,9 +122,9 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
 pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
-        let mut cfg = CheckCfg::default();
+        let mut check_cfg = CheckCfg::default();
 
-        'specs: for s in specs {
+        for s in specs {
             let sess = ParseSess::with_silent_emitter(Some(format!(
                 "this error occurred on the command line: `--check-cfg={s}`"
             )));
@@ -137,40 +138,54 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                             concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
                             s
                         ),
-                    );
+                    )
                 };
             }
 
+            let expected_error = || {
+                error!(
+                    "expected `names(name1, name2, ... nameN)` or \
+                        `values(name, \"value1\", \"value2\", ... \"valueN\")`"
+                )
+            };
+
             match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
                 Ok(mut parser) => match parser.parse_meta_item() {
                     Ok(meta_item) if parser.token == token::Eof => {
                         if let Some(args) = meta_item.meta_item_list() {
                             if meta_item.has_name(sym::names) {
-                                let names_valid =
-                                    cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
+                                check_cfg.exhaustive_names = true;
                                 for arg in args {
                                     if arg.is_word() && arg.ident().is_some() {
                                         let ident = arg.ident().expect("multi-segment cfg key");
-                                        names_valid.insert(ident.name.to_string());
+                                        check_cfg
+                                            .expecteds
+                                            .entry(ident.name.to_string())
+                                            .or_insert(ExpectedValues::Any);
                                     } else {
                                         error!("`names()` arguments must be simple identifiers");
                                     }
                                 }
-                                continue 'specs;
                             } else if meta_item.has_name(sym::values) {
                                 if let Some((name, values)) = args.split_first() {
                                     if name.is_word() && name.ident().is_some() {
                                         let ident = name.ident().expect("multi-segment cfg key");
-                                        let ident_values = cfg
-                                            .values_valid
+                                        let expected_values = check_cfg
+                                            .expecteds
                                             .entry(ident.name.to_string())
-                                            .or_insert_with(|| FxHashSet::default());
+                                            .or_insert_with(|| {
+                                                ExpectedValues::Some(FxHashSet::default())
+                                            });
+
+                                        let ExpectedValues::Some(expected_values) = expected_values else {
+                                            bug!("shoudn't be possible")
+                                        };
 
                                         for val in values {
                                             if let Some(LitKind::Str(s, _)) =
                                                 val.lit().map(|lit| &lit.kind)
                                             {
-                                                ident_values.insert(s.to_string());
+                                                expected_values.insert(Some(s.to_string()));
                                             } else {
                                                 error!(
                                                     "`values()` arguments must be string literals"
@@ -178,35 +193,40 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
                                             }
                                         }
 
-                                        continue 'specs;
+                                        if values.is_empty() {
+                                            expected_values.insert(None);
+                                        }
                                     } else {
                                         error!(
                                             "`values()` first argument must be a simple identifier"
                                         );
                                     }
                                 } else if args.is_empty() {
-                                    cfg.well_known_values = true;
-                                    continue 'specs;
+                                    check_cfg.exhaustive_values = true;
+                                } else {
+                                    expected_error();
                                 }
+                            } else {
+                                expected_error();
                             }
+                        } else {
+                            expected_error();
                         }
                     }
-                    Ok(..) => {}
-                    Err(err) => err.cancel(),
+                    Ok(..) => expected_error(),
+                    Err(err) => {
+                        err.cancel();
+                        expected_error();
+                    }
                 },
-                Err(errs) => drop(errs),
+                Err(errs) => {
+                    drop(errs);
+                    expected_error();
+                }
             }
-
-            error!(
-                "expected `names(name1, name2, ... nameN)` or \
-                `values(name, \"value1\", \"value2\", ... \"valueN\")`"
-            );
         }
 
-        if let Some(names_valid) = &mut cfg.names_valid {
-            names_valid.extend(cfg.values_valid.keys().cloned());
-        }
-        cfg
+        check_cfg
     })
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a0c576234f9..1bae771e373 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -69,6 +69,7 @@ where
         is_private_dep: false,
         add_prelude: true,
         nounused_dep: false,
+        force: false,
     }
 }
 
@@ -547,6 +548,7 @@ fn test_codegen_options_tracking_hash() {
     untracked!(ar, String::from("abc"));
     untracked!(codegen_units, Some(42));
     untracked!(default_linker_libraries, true);
+    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(extra_filename, String::from("extra-filename"));
     untracked!(incremental, Some(String::from("abc")));
     // `link_arg` is omitted because it just forwards to `link_args`.
@@ -651,7 +653,6 @@ fn test_unstable_options_tracking_hash() {
     untracked!(assert_incr_state, Some(String::from("loaded")));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
-    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
     untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b3f4b5cd5e5..c07dc19a0ac 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -186,12 +186,16 @@ pub enum LiteralKind {
     Str { terminated: bool },
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
+    /// `c"abc"`, `c"abc`
+    CStr { terminated: bool },
     /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
     /// an invalid literal.
     RawStr { n_hashes: Option<u8> },
     /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
     /// indicates an invalid literal.
     RawByteStr { n_hashes: Option<u8> },
+    /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
+    RawCStr { n_hashes: Option<u8> },
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -357,39 +361,18 @@ impl Cursor<'_> {
             },
 
             // Byte literal, byte string literal, raw byte string literal or identifier.
-            'b' => match (self.first(), self.second()) {
-                ('\'', _) => {
-                    self.bump();
-                    let terminated = self.single_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = Byte { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('"', _) => {
-                    self.bump();
-                    let terminated = self.double_quoted_string();
-                    let suffix_start = self.pos_within_token();
-                    if terminated {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = ByteStr { terminated };
-                    Literal { kind, suffix_start }
-                }
-                ('r', '"') | ('r', '#') => {
-                    self.bump();
-                    let res = self.raw_double_quoted_string(2);
-                    let suffix_start = self.pos_within_token();
-                    if res.is_ok() {
-                        self.eat_literal_suffix();
-                    }
-                    let kind = RawByteStr { n_hashes: res.ok() };
-                    Literal { kind, suffix_start }
-                }
-                _ => self.ident_or_unknown_prefix(),
-            },
+            'b' => self.c_or_byte_string(
+                |terminated| ByteStr { terminated },
+                |n_hashes| RawByteStr { n_hashes },
+                Some(|terminated| Byte { terminated }),
+            ),
+
+            // c-string literal, raw c-string literal or identifier.
+            'c' => self.c_or_byte_string(
+                |terminated| CStr { terminated },
+                |n_hashes| RawCStr { n_hashes },
+                None,
+            ),
 
             // Identifier (this should be checked after other variant that can
             // start as identifier).
@@ -553,6 +536,47 @@ impl Cursor<'_> {
         }
     }
 
+    fn c_or_byte_string(
+        &mut self,
+        mk_kind: impl FnOnce(bool) -> LiteralKind,
+        mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
+        single_quoted: Option<fn(bool) -> LiteralKind>,
+    ) -> TokenKind {
+        match (self.first(), self.second(), single_quoted) {
+            ('\'', _, Some(mk_kind)) => {
+                self.bump();
+                let terminated = self.single_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('"', _, _) => {
+                self.bump();
+                let terminated = self.double_quoted_string();
+                let suffix_start = self.pos_within_token();
+                if terminated {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind(terminated);
+                Literal { kind, suffix_start }
+            }
+            ('r', '"', _) | ('r', '#', _) => {
+                self.bump();
+                let res = self.raw_double_quoted_string(2);
+                let suffix_start = self.pos_within_token();
+                if res.is_ok() {
+                    self.eat_literal_suffix();
+                }
+                let kind = mk_kind_raw(res.ok());
+                Literal { kind, suffix_start }
+            }
+            _ => self.ident_or_unknown_prefix(),
+        }
+    }
+
     fn number(&mut self, first_digit: char) -> LiteralKind {
         debug_assert!('0' <= self.prev() && self.prev() <= '9');
         let mut base = Base::Decimal;
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index bb4d91247b8..c9ad54d8d98 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -86,10 +86,45 @@ where
             let res = unescape_char_or_byte(&mut chars, mode == Mode::Byte);
             callback(0..(src.len() - chars.as_str().len()), res);
         }
-        Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(src, mode == Mode::ByteStr, callback),
+        Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
+
         Mode::RawStr | Mode::RawByteStr => {
             unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
         }
+        Mode::CStr | Mode::RawCStr => unreachable!(),
+    }
+}
+
+/// A unit within CStr. Must not be a nul character.
+pub enum CStrUnit {
+    Byte(u8),
+    Char(char),
+}
+
+impl From<u8> for CStrUnit {
+    fn from(value: u8) -> Self {
+        CStrUnit::Byte(value)
+    }
+}
+
+impl From<char> for CStrUnit {
+    fn from(value: char) -> Self {
+        CStrUnit::Char(value)
+    }
+}
+
+pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
+where
+    F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
+{
+    if mode == Mode::RawCStr {
+        unescape_raw_str_or_raw_byte_str(
+            src,
+            mode.characters_should_be_ascii(),
+            &mut |r, result| callback(r, result.map(CStrUnit::Char)),
+        );
+    } else {
+        unescape_str_common(src, mode, callback);
     }
 }
 
@@ -114,34 +149,69 @@ pub enum Mode {
     ByteStr,
     RawStr,
     RawByteStr,
+    CStr,
+    RawCStr,
 }
 
 impl Mode {
     pub fn in_double_quotes(self) -> bool {
         match self {
-            Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+            Mode::Str
+            | Mode::ByteStr
+            | Mode::RawStr
+            | Mode::RawByteStr
+            | Mode::CStr
+            | Mode::RawCStr => true,
             Mode::Char | Mode::Byte => false,
         }
     }
 
-    pub fn is_byte(self) -> bool {
+    /// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
+    pub fn ascii_escapes_should_be_ascii(self) -> bool {
+        match self {
+            Mode::Char | Mode::Str | Mode::RawStr => true,
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Whether characters within the literal must be within the ASCII range
+    pub fn characters_should_be_ascii(self) -> bool {
         match self {
             Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
-            Mode::Char | Mode::Str | Mode::RawStr => false,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    /// Byte literals do not allow unicode escape.
+    pub fn is_unicode_escape_disallowed(self) -> bool {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
+            Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+        }
+    }
+
+    pub fn prefix_noraw(self) -> &'static str {
+        match self {
+            Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
+            Mode::CStr | Mode::RawCStr => "c",
+            Mode::Char | Mode::Str | Mode::RawStr => "",
         }
     }
 }
 
-fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
+fn scan_escape<T: From<u8> + From<char>>(
+    chars: &mut Chars<'_>,
+    mode: Mode,
+) -> Result<T, EscapeError> {
     // Previous character was '\\', unescape what follows.
     let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
-        '"' => '"',
-        'n' => '\n',
-        'r' => '\r',
-        't' => '\t',
-        '\\' => '\\',
-        '\'' => '\'',
-        '0' => '\0',
+        '"' => b'"',
+        'n' => b'\n',
+        'r' => b'\r',
+        't' => b'\t',
+        '\\' => b'\\',
+        '\'' => b'\'',
+        '0' => b'\0',
 
         'x' => {
             // Parse hexadecimal character code.
@@ -154,76 +224,78 @@ fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError
 
             let value = hi * 16 + lo;
 
-            // For a non-byte literal verify that it is within ASCII range.
-            if !is_byte && !is_ascii(value) {
+            if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) {
                 return Err(EscapeError::OutOfRangeHexEscape);
             }
-            let value = value as u8;
 
-            value as char
+            value as u8
         }
 
-        'u' => {
-            // We've parsed '\u', now we have to parse '{..}'.
-
-            if chars.next() != Some('{') {
-                return Err(EscapeError::NoBraceInUnicodeEscape);
-            }
-
-            // First character must be a hexadecimal digit.
-            let mut n_digits = 1;
-            let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
-                '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
-                '}' => return Err(EscapeError::EmptyUnicodeEscape),
-                c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
-            };
-
-            // First character is valid, now parse the rest of the number
-            // and closing brace.
-            loop {
-                match chars.next() {
-                    None => return Err(EscapeError::UnclosedUnicodeEscape),
-                    Some('_') => continue,
-                    Some('}') => {
-                        if n_digits > 6 {
-                            return Err(EscapeError::OverlongUnicodeEscape);
-                        }
-
-                        // Incorrect syntax has higher priority for error reporting
-                        // than unallowed value for a literal.
-                        if is_byte {
-                            return Err(EscapeError::UnicodeEscapeInByte);
-                        }
-
-                        break std::char::from_u32(value).ok_or_else(|| {
-                            if value > 0x10FFFF {
-                                EscapeError::OutOfRangeUnicodeEscape
-                            } else {
-                                EscapeError::LoneSurrogateUnicodeEscape
-                            }
-                        })?;
-                    }
-                    Some(c) => {
-                        let digit: u32 =
-                            c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
-                        n_digits += 1;
-                        if n_digits > 6 {
-                            // Stop updating value since we're sure that it's incorrect already.
-                            continue;
-                        }
-                        value = value * 16 + digit;
-                    }
-                };
-            }
-        }
+        'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into),
         _ => return Err(EscapeError::InvalidEscape),
     };
-    Ok(res)
+    Ok(res.into())
+}
+
+fn scan_unicode(
+    chars: &mut Chars<'_>,
+    is_unicode_escape_disallowed: bool,
+) -> Result<char, EscapeError> {
+    // We've parsed '\u', now we have to parse '{..}'.
+
+    if chars.next() != Some('{') {
+        return Err(EscapeError::NoBraceInUnicodeEscape);
+    }
+
+    // First character must be a hexadecimal digit.
+    let mut n_digits = 1;
+    let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+        '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+        '}' => return Err(EscapeError::EmptyUnicodeEscape),
+        c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+    };
+
+    // First character is valid, now parse the rest of the number
+    // and closing brace.
+    loop {
+        match chars.next() {
+            None => return Err(EscapeError::UnclosedUnicodeEscape),
+            Some('_') => continue,
+            Some('}') => {
+                if n_digits > 6 {
+                    return Err(EscapeError::OverlongUnicodeEscape);
+                }
+
+                // Incorrect syntax has higher priority for error reporting
+                // than unallowed value for a literal.
+                if is_unicode_escape_disallowed {
+                    return Err(EscapeError::UnicodeEscapeInByte);
+                }
+
+                break std::char::from_u32(value).ok_or_else(|| {
+                    if value > 0x10FFFF {
+                        EscapeError::OutOfRangeUnicodeEscape
+                    } else {
+                        EscapeError::LoneSurrogateUnicodeEscape
+                    }
+                });
+            }
+            Some(c) => {
+                let digit: u32 = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+                n_digits += 1;
+                if n_digits > 6 {
+                    // Stop updating value since we're sure that it's incorrect already.
+                    continue;
+                }
+                value = value * 16 + digit;
+            }
+        };
+    }
 }
 
 #[inline]
-fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
-    if is_byte && !c.is_ascii() {
+fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
+    if characters_should_be_ascii && !c.is_ascii() {
         // Byte literal can't be a non-ascii character.
         Err(EscapeError::NonAsciiCharInByte)
     } else {
@@ -234,7 +306,7 @@ fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
 fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
     let c = chars.next().ok_or(EscapeError::ZeroChars)?;
     let res = match c {
-        '\\' => scan_escape(chars, is_byte),
+        '\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
         '\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
         '\r' => Err(EscapeError::BareCarriageReturn),
         _ => ascii_check(c, is_byte),
@@ -247,9 +319,9 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, E
 
 /// Takes a contents of a string literal (without quotes) and produces a
 /// sequence of escaped characters or errors.
-fn unescape_str_or_byte_str<F>(src: &str, is_byte: bool, callback: &mut F)
+fn unescape_str_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F)
 where
-    F: FnMut(Range<usize>, Result<char, EscapeError>),
+    F: FnMut(Range<usize>, Result<T, EscapeError>),
 {
     let mut chars = src.chars();
 
@@ -266,47 +338,49 @@ where
                         // if unescaped '\' character is followed by '\n'.
                         // For details see [Rust language reference]
                         // (https://doc.rust-lang.org/reference/tokens.html#string-literals).
-                        skip_ascii_whitespace(&mut chars, start, callback);
+                        skip_ascii_whitespace(&mut chars, start, &mut |range, err| {
+                            callback(range, Err(err))
+                        });
                         continue;
                     }
-                    _ => scan_escape(&mut chars, is_byte),
+                    _ => scan_escape::<T>(&mut chars, mode),
                 }
             }
-            '\n' => Ok('\n'),
-            '\t' => Ok('\t'),
+            '\n' => Ok(b'\n'.into()),
+            '\t' => Ok(b'\t'.into()),
             '"' => Err(EscapeError::EscapeOnlyChar),
             '\r' => Err(EscapeError::BareCarriageReturn),
-            _ => ascii_check(c, is_byte),
+            _ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
         };
         let end = src.len() - chars.as_str().len();
-        callback(start..end, res);
+        callback(start..end, res.map(Into::into));
     }
+}
 
-    fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
-    where
-        F: FnMut(Range<usize>, Result<char, EscapeError>),
-    {
-        let tail = chars.as_str();
-        let first_non_space = tail
-            .bytes()
-            .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
-            .unwrap_or(tail.len());
-        if tail[1..first_non_space].contains('\n') {
-            // The +1 accounts for the escaping slash.
-            let end = start + first_non_space + 1;
-            callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
-        }
-        let tail = &tail[first_non_space..];
-        if let Some(c) = tail.chars().nth(0) {
-            if c.is_whitespace() {
-                // For error reporting, we would like the span to contain the character that was not
-                // skipped. The +1 is necessary to account for the leading \ that started the escape.
-                let end = start + first_non_space + c.len_utf8() + 1;
-                callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
-            }
-        }
-        *chars = tail.chars();
+fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+where
+    F: FnMut(Range<usize>, EscapeError),
+{
+    let tail = chars.as_str();
+    let first_non_space = tail
+        .bytes()
+        .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+        .unwrap_or(tail.len());
+    if tail[1..first_non_space].contains('\n') {
+        // The +1 accounts for the escaping slash.
+        let end = start + first_non_space + 1;
+        callback(start..end, EscapeError::MultipleSkippedLinesWarning);
     }
+    let tail = &tail[first_non_space..];
+    if let Some(c) = tail.chars().nth(0) {
+        if c.is_whitespace() {
+            // For error reporting, we would like the span to contain the character that was not
+            // skipped. The +1 is necessary to account for the leading \ that started the escape.
+            let end = start + first_non_space + c.len_utf8() + 1;
+            callback(start..end, EscapeError::UnskippedWhitespaceWarning);
+        }
+    }
+    *chars = tail.chars();
 }
 
 /// Takes a contents of a string literal (without quotes) and produces a
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index aeb791901bd..0b7a704eb57 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -63,6 +63,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -116,8 +117,7 @@ impl EarlyLintPass for WhileTrue {
     #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::While(cond, _, label) = &e.kind
-            && let cond = pierce_parens(cond)
-            && let ast::ExprKind::Lit(token_lit) = cond.kind
+            && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
             && let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
             && !cond.span.from_expansion()
         {
@@ -546,32 +546,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        match it.kind {
-            hir::ItemKind::Trait(..) => {
-                // Issue #11592: traits are always considered exported, even when private.
-                if cx.tcx.visibility(it.owner_id)
-                    == ty::Visibility::Restricted(
-                        cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
-                    )
-                {
-                    return;
-                }
-            }
-            hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::Macro(..)
-            | hir::ItemKind::Mod(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Union(..)
-            | hir::ItemKind::Const(..)
-            | hir::ItemKind::Static(..) => {}
-
-            _ => return,
-        };
+        // Previously the Impl and Use types have been excluded from missing docs,
+        // so we will continue to exclude them for compatibility
+        if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) = it.kind {
+            return;
+        }
 
         let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
-
         self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
     }
 
@@ -3306,16 +3287,15 @@ impl EarlyLintPass for UnexpectedCfgs {
         let cfg = &cx.sess().parse_sess.config;
         let check_cfg = &cx.sess().parse_sess.check_config;
         for &(name, value) in cfg {
-            if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
-                cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
-                    name,
-                });
-            }
-            if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
-                cx.emit_lint(
-                    UNEXPECTED_CFGS,
-                    BuiltinUnexpectedCliConfigValue { name, value },
-                );
+            match check_cfg.expecteds.get(&name) {
+                Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
+                    let value = value.unwrap_or(kw::Empty);
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
+                }
+                None if check_cfg.exhaustive_names => {
+                    cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
+                }
+                _ => { /* expected */ }
             }
         }
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index d4898ffe883..53d7cf74cde 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,6 +36,7 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::config::ExpectedValues;
 use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
@@ -768,22 +769,52 @@ pub trait LintContext: Sized {
                     db.help(help);
                     db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
-                    let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
-                        bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
-                    };
-                    let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+                BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
+                    let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
 
                     // Suggest the most probable if we found one
                     if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
-                        db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
+                        if let Some(ExpectedValues::Some(best_match_values)) =
+                            sess.parse_sess.check_config.expecteds.get(&best_match) {
+                            let mut possibilities = best_match_values.iter()
+                                .flatten()
+                                .map(Symbol::as_str)
+                                .collect::<Vec<_>>();
+                            possibilities.sort();
+
+                            if let Some((value, value_span)) = value {
+                                if best_match_values.contains(&Some(value)) {
+                                    db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+                                } else if best_match_values.contains(&None) {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+                                } else if let Some(first_value) = possibilities.first() {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
+                                } else {
+                                    db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect);
+                                };
+                            } else {
+                                db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                            }
+
+                            if !possibilities.is_empty() {
+                                let possibilities = possibilities.join("`, `");
+                                db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+                            }
+                        } else {
+                            db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+                        }
                     }
                 },
-                BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
-                    let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+                BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
+                    let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
                         bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
                     };
-                    let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
+                    let mut have_none_possibility = false;
+                    let possibilities: Vec<Symbol> = values.iter()
+                        .inspect(|a| have_none_possibility |= a.is_none())
+                        .copied()
+                        .flatten()
+                        .collect();
 
                     // Show the full list if all possible values for a given name, but don't do it
                     // for names as the possibilities could be very long
@@ -792,17 +823,24 @@ pub trait LintContext: Sized {
                             let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
                             possibilities.sort();
 
-                            let possibilities = possibilities.join(", ");
-                            db.note(format!("expected values for `{name}` are: {possibilities}"));
+                            let possibilities = possibilities.join("`, `");
+                            let none = if have_none_possibility { "(none), " } else { "" };
+
+                            db.note(format!("expected values for `{name}` are: {none}`{possibilities}`"));
                         }
 
-                        // Suggest the most probable if we found one
-                        if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
-                            db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+                        if let Some((value, value_span)) = value {
+                            // Suggest the most probable if we found one
+                            if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+                                db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+
+                            }
+                        } else if let &[first_possibility] = &possibilities[..] {
+                            db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
                         }
-                    } else {
+                    } else if have_none_possibility {
                         db.note(format!("no expected value for `{name}`"));
-                        if name != sym::feature {
+                        if let Some((_value, value_span)) = value {
                             db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
                         }
                     }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 595b50c4063..0082aaa4a38 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -478,8 +478,10 @@ impl EarlyLintPass for Diagnostics {
         }
         if !segments.iter().all(|(name, args)| {
             let arg = match name.as_str() {
-                "struct_span_err" | "span_note" | "span_label" | "span_help" => &args[1],
-                "note" | "help" => &args[0],
+                "struct_span_err" | "span_note" | "span_label" | "span_help" if args.len() == 2 => {
+                    &args[1]
+                }
+                "note" | "help" if args.len() == 1 => &args[0],
                 _ => {
                     return false;
                 }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7ea472ed504..e27e322db88 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -496,7 +496,8 @@ pub enum BuiltinLintDiagnostics {
     BreakWithLabelAndLoop(Span),
     NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
-    UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
+    UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
     DeprecatedWhereclauseLocation(Span, String),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 1acdc95ca8d..5ec3b95225d 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -297,7 +297,6 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
   report_fatal_error("Bad RelocModel.");
 }
 
-#ifdef LLVM_RUSTLLVM
 /// getLongestEntryLength - Return the length of the longest entry in the table.
 template<typename KV>
 static size_t getLongestEntryLength(ArrayRef<KV> Table) {
@@ -307,56 +306,68 @@ static size_t getLongestEntryLength(ArrayRef<KV> Table) {
   return MaxLen;
 }
 
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
+extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) {
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch();
   const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
+
+#if LLVM_VERSION_GE(17, 0)
+  const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions();
+#elif defined(LLVM_RUSTLLVM)
   const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable();
+#else
+  printf("Full target CPU help is not supported by this LLVM version.\n\n");
+  SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} };
+  const ArrayRef<SubtargetSubTypeKV> CPUTable = TargetCPUKV;
+#endif
   unsigned MaxCPULen = getLongestEntryLength(CPUTable);
 
   printf("Available CPUs for this target:\n");
   // Don't print the "native" entry when the user specifies --target with a
   // different arch since that could be wrong or misleading.
   if (HostArch == TargetArch) {
+    MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native"));
     const StringRef HostCPU = sys::getHostCPUName();
     printf("    %-*s - Select the CPU of the current host (currently %.*s).\n",
       MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
   }
-  for (auto &CPU : CPUTable)
-    printf("    %-*s\n", MaxCPULen, CPU.Key);
-  printf("\n");
+  for (auto &CPU : CPUTable) {
+    // Compare cpu against current target to label the default
+    if (strcmp(CPU.Key, TargetCPU) == 0) {
+      printf("    %-*s - This is the default target CPU"
+      " for the current build target (currently %s).",
+        MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str());
+    }
+    else {
+      printf("    %-*s", MaxCPULen, CPU.Key);
+    }
+    printf("\n");
+  }
 }
 
 extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
+#ifdef LLVM_RUSTLLVM
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
   return FeatTable.size();
+#else
+  return 0;
+#endif
 }
 
 extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
                                          const char** Feature, const char** Desc) {
+#ifdef LLVM_RUSTLLVM
   const TargetMachine *Target = unwrap(TM);
   const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
   const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
   const SubtargetFeatureKV Feat = FeatTable[Index];
   *Feature = Feat.Key;
   *Desc = Feat.Desc;
-}
-
-#else
-
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
-  printf("Target CPU help is not supported by this LLVM version.\n\n");
-}
-
-extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
-  return 0;
-}
-
-extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
 #endif
+}
 
 extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
   StringRef Name = sys::getHostCPUName();
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index cadb6b1e23f..49acd71b3e1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -831,6 +831,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
   return wrap(Sub);
 }
 
+extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
+    LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
+    const char *Name, size_t NameLen,
+    const char *LinkageName, size_t LinkageNameLen,
+    LLVMMetadataRef File, unsigned LineNo,
+    LLVMMetadataRef Ty, LLVMRustDIFlags Flags,
+    LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
+  DITemplateParameterArray TParams =
+      DITemplateParameterArray(unwrap<MDTuple>(TParam));
+  DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
+  DINode::DIFlags llvmFlags = fromRust(Flags);
+  DISubprogram *Sub = Builder->createMethod(
+      unwrapDI<DIScope>(Scope),
+      StringRef(Name, NameLen),
+      StringRef(LinkageName, LinkageNameLen),
+      unwrapDI<DIFile>(File), LineNo,
+      unwrapDI<DISubroutineType>(Ty),
+      0, 0, nullptr, // VTable params aren't used
+      llvmFlags, llvmSPFlags, TParams);
+  return wrap(Sub);
+}
+
 extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateBasicType(
     LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen,
     uint64_t SizeInBits, unsigned Encoding) {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 01b69966ca9..e6e7d25773e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -865,6 +865,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         }
     }
 
+    fn inject_forced_externs(&mut self) {
+        for (name, entry) in self.sess.opts.externs.iter() {
+            if entry.force {
+                let name_interned = Symbol::intern(name);
+                if !self.used_extern_options.contains(&name_interned) {
+                    self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
+                }
+            }
+        }
+    }
+
     fn inject_dependency_if(
         &self,
         krate: CrateNum,
@@ -913,7 +924,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
             }
-            if entry.nounused_dep {
+            if entry.nounused_dep || entry.force {
                 // We're not worried about this one
                 continue;
             }
@@ -942,6 +953,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
     }
 
     pub fn postprocess(&mut self, krate: &ast::Crate) {
+        self.inject_forced_externs();
         self.inject_profiler_runtime(krate);
         self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b43dcf3e5a1..c83c47e722b 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -161,14 +161,6 @@ impl<'tcx> Collector<'tcx> {
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
                                     sess.emit_err(errors::FrameworkOnlyWindows { span });
-                                } else if !features.raw_dylib && sess.target.arch == "x86" {
-                                    feature_err(
-                                        &sess.parse_sess,
-                                        sym::raw_dylib,
-                                        span,
-                                        "link kind `raw-dylib` is unstable on x86",
-                                    )
-                                    .emit();
                                 }
                                 NativeLibKind::RawDylib
                             }
@@ -251,16 +243,6 @@ impl<'tcx> Collector<'tcx> {
                                 continue;
                             }
                         };
-                        if !features.raw_dylib {
-                            let span = item.name_value_literal_span().unwrap();
-                            feature_err(
-                                &sess.parse_sess,
-                                sym::raw_dylib,
-                                span,
-                                "import name type is unstable",
-                            )
-                            .emit();
-                        }
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 967fed687b6..aeb6a1601fc 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -64,7 +64,7 @@ impl EffectiveVisibility {
         self.at_level(level).is_public()
     }
 
-    pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
+    pub const fn from_vis(vis: Visibility) -> EffectiveVisibility {
         EffectiveVisibility {
             direct: vis,
             reexported: vis,
@@ -72,6 +72,18 @@ impl EffectiveVisibility {
             reachable_through_impl_trait: vis,
         }
     }
+
+    #[must_use]
+    pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self {
+        for l in Level::all_levels() {
+            let rhs_vis = self.at_level_mut(l);
+            let lhs_vis = *lhs.at_level(l);
+            if rhs_vis.is_at_least(lhs_vis, tcx) {
+                *rhs_vis = lhs_vis;
+            };
+        }
+        self
+    }
 }
 
 /// Holds a map of effective visibilities for reachable HIR nodes.
@@ -137,24 +149,6 @@ impl EffectiveVisibilities {
         };
     }
 
-    pub fn set_public_at_level(
-        &mut self,
-        id: LocalDefId,
-        lazy_private_vis: impl FnOnce() -> Visibility,
-        level: Level,
-    ) {
-        let mut effective_vis = self
-            .effective_vis(id)
-            .copied()
-            .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis()));
-        for l in Level::all_levels() {
-            if l <= level {
-                *effective_vis.at_level_mut(l) = Visibility::Public;
-            }
-        }
-        self.map.insert(id, effective_vis);
-    }
-
     pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
         if !cfg!(debug_assertions) {
             return;
@@ -219,7 +213,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
     pub fn update(
         &mut self,
         id: Id,
-        nominal_vis: Visibility,
+        nominal_vis: Option<Visibility>,
         lazy_private_vis: impl FnOnce() -> Visibility,
         inherited_effective_vis: EffectiveVisibility,
         level: Level,
@@ -243,12 +237,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
                 if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
                     && level != l)
                 {
-                    calculated_effective_vis =
-                        if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
-                            inherited_effective_vis_at_level
-                        } else {
-                            nominal_vis
-                        };
+                    calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
+                        nominal_vis
+                    } else {
+                        inherited_effective_vis_at_level
+                    }
                 }
                 // effective visibility can't be decreased at next update call for the
                 // same id
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index be2657d25a6..b425c7600ac 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -569,7 +569,7 @@ rustc_queries! {
     /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
     /// subset of super-predicates that reference traits that define the given associated type.
     /// This is used to avoid cycles in resolving types like `T::Item`.
-    query super_predicates_that_define_assoc_type(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+    query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing the super traits of `{}` with associated type name `{}`",
             tcx.def_path_str(key.0),
             key.1
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index c2375564208..8366567c2c3 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -444,6 +444,10 @@ pub enum ObligationCauseCode<'tcx> {
     AscribeUserTypeProvePredicate(Span),
 
     RustCall,
+
+    /// Obligations to prove that a `std::ops::Drop` impl is not stronger than
+    /// the ADT it's being implemented for.
+    DropImpl,
 }
 
 /// The 'location' at which we try to perform HIR-based wf checking.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c62254cd79c..a2e248e45ca 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1567,11 +1567,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
     /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
-    pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+    pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
         self.super_traits_of(trait_def_id).any(|trait_did| {
             self.associated_items(trait_did)
-                .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did)
-                .is_some()
+                .filter_by_name_unhygienic(assoc_name.name)
+                .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did))
         })
     }
 
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index cc86cba6fda..6c8f4af7594 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -385,7 +385,7 @@ impl<'tcx> Instance<'tcx> {
     /// couldn't complete due to errors elsewhere - this is distinct
     /// from `Ok(None)` to avoid misleading diagnostics when an error
     /// has already been/will be emitted, for the original cause
-    #[instrument(level = "debug", skip(tcx))]
+    #[instrument(level = "debug", skip(tcx), ret)]
     pub fn resolve(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6ac9f950450..b7e780b94ef 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2633,6 +2633,12 @@ macro_rules! define_print_and_forward_display {
 #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
 
+impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintOnlyTraitPath<'tcx> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        self.to_string().into_diagnostic_arg()
+    }
+}
+
 impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Display::fmt(self, f)
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index fbcfd433724..59549435233 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -146,6 +146,12 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
             let id = tcx.allocate_bytes(data);
             ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
         }
+        (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+        {
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+            let allocation = tcx.mk_const_alloc(allocation);
+            ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+        }
         (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
             ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
         }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b1c0dedd3c7..51e90489002 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
 use crate::errors;
 use crate::lexer::unicode_chars::UNICODE_ARRAY;
 use crate::make_unclosed_delims_error;
@@ -6,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey};
-use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::Cursor;
 use rustc_lexer::{Base, DocStyle, RawStrError};
 use rustc_session::lint::builtin::{
@@ -204,6 +206,9 @@ impl<'a> StringReader<'a> {
                 rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
                     let suffix_start = start + BytePos(suffix_start);
                     let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+                    if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind {
+                        self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos));
+                    }
                     let suffix = if suffix_start < self.pos {
                         let string = self.str_from(suffix_start);
                         if string == "_" {
@@ -415,6 +420,16 @@ impl<'a> StringReader<'a> {
                 }
                 self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
             }
+            rustc_lexer::LiteralKind::CStr { terminated } => {
+                if !terminated {
+                    self.sess.span_diagnostic.span_fatal_with_code(
+                        self.mk_sp(start + BytePos(1), end),
+                        "unterminated C string",
+                        error_code!(E0767),
+                    )
+                }
+                self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" "
+            }
             rustc_lexer::LiteralKind::RawStr { n_hashes } => {
                 if let Some(n_hashes) = n_hashes {
                     let n = u32::from(n_hashes);
@@ -433,6 +448,15 @@ impl<'a> StringReader<'a> {
                     self.report_raw_str_error(start, 2);
                 }
             }
+            rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    let kind = token::CStrRaw(n_hashes);
+                    self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "##
+                } else {
+                    self.report_raw_str_error(start, 2);
+                }
+            }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 if empty_int {
                     let span = self.mk_sp(start, end);
@@ -648,7 +672,7 @@ impl<'a> StringReader<'a> {
         self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
     }
 
-    fn cook_quoted(
+    fn cook_common(
         &self,
         kind: token::LitKind,
         mode: Mode,
@@ -656,12 +680,13 @@ impl<'a> StringReader<'a> {
         end: BytePos,
         prefix_len: u32,
         postfix_len: u32,
+        unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)),
     ) -> (token::LitKind, Symbol) {
         let mut has_fatal_err = false;
         let content_start = start + BytePos(prefix_len);
         let content_end = end - BytePos(postfix_len);
         let lit_content = self.str_from_to(content_start, content_end);
-        unescape::unescape_literal(lit_content, mode, &mut |range, result| {
+        unescape(lit_content, mode, &mut |range, result| {
             // Here we only check for errors. The actual unescaping is done later.
             if let Err(err) = result {
                 let span_with_quotes = self.mk_sp(start, end);
@@ -692,6 +717,38 @@ impl<'a> StringReader<'a> {
             (token::Err, self.symbol_from_to(start, end))
         }
     }
+
+    fn cook_quoted(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_literal(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
+
+    fn cook_c_string(
+        &self,
+        kind: token::LitKind,
+        mode: Mode,
+        start: BytePos,
+        end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) -> (token::LitKind, Symbol) {
+        self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+            unescape::unescape_c_string(src, mode, &mut |span, result| {
+                callback(span, result.map(drop))
+            })
+        })
+    }
 }
 
 pub fn nfc_normalize(string: &str) -> Symbol {
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index d8bcf816fb2..eb9625f923a 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error(
                 }
             };
             let sugg = sugg.unwrap_or_else(|| {
-                let is_byte = mode.is_byte();
-                let prefix = if is_byte { "b" } else { "" };
+                let prefix = mode.prefix_noraw();
                 let mut escaped = String::with_capacity(lit.len());
                 let mut chrs = lit.chars().peekable();
                 while let Some(first) = chrs.next() {
@@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error(
                     };
                 }
                 let sugg = format!("{prefix}\"{escaped}\"");
-                MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+                MoreThanOneCharSugg::Quotes {
+                    span: span_with_quotes,
+                    is_byte: mode == Mode::Byte,
+                    sugg,
+                }
             });
             handler.emit_err(UnescapeError::MoreThanOneChar {
                 span: span_with_quotes,
@@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error(
                 char_span,
                 escaped_sugg: c.escape_default().to_string(),
                 escaped_msg: escaped_char(c),
-                byte: mode.is_byte(),
+                byte: mode == Mode::Byte,
             });
         }
         EscapeError::BareCarriageReturn => {
@@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error(
         EscapeError::InvalidEscape => {
             let (c, span) = last_char();
 
-            let label =
-                if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
+            let label = if mode == Mode::Byte || mode == Mode::ByteStr {
+                "unknown byte escape"
+            } else {
+                "unknown character escape"
+            };
             let ec = escaped_char(c);
             let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
             diag.span_label(span, label);
-            if c == '{' || c == '}' && !mode.is_byte() {
+            if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
                 diag.help(
                     "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                 );
@@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error(
                      version control settings",
                 );
             } else {
-                if !mode.is_byte() {
+                if mode == Mode::Str || mode == Mode::Char {
                     diag.span_suggestion(
                         span_with_quotes,
                         "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index f58f8919e5c..018eddea4b0 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1448,8 +1448,19 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
+        let maybe_eq_tok = self.prev_token.clone();
         let (qself, path) = if self.eat_lt() {
-            let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+            let lt_span = self.prev_token.span;
+            let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
+                // Suggests using '<=' if there is an error parsing qpath when the previous token
+                // is an '=' token. Only emits suggestion if the '<' token and '=' token are
+                // directly adjacent (i.e. '=<')
+                if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+                    let eq_lt = maybe_eq_tok.span.to(lt_span);
+                    err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
+                }
+                err
+            })?;
             (Some(qself), path)
         } else {
             (None, self.parse_path(PathStyle::Expr)?)
@@ -1870,6 +1881,7 @@ impl<'a> Parser<'a> {
         let recovered = self.recover_after_dot();
         let token = recovered.as_ref().unwrap_or(&self.token);
         let span = token.span;
+
         token::Lit::from_token(token).map(|token_lit| {
             self.bump();
             (token_lit, span)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 04ac585076f..b738ce35ada 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -25,7 +25,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
@@ -38,7 +38,7 @@ use rustc_span::Span;
 
 use std::marker::PhantomData;
 use std::ops::ControlFlow;
-use std::{cmp, fmt, mem};
+use std::{fmt, mem};
 
 use errors::{
     FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
@@ -375,8 +375,9 @@ impl VisibilityLike for ty::Visibility {
         min(find.tcx.local_visibility(def_id), find.min, find.tcx)
     }
 }
-impl VisibilityLike for Option<Level> {
-    const MAX: Self = Some(Level::Direct);
+
+impl VisibilityLike for Option<EffectiveVisibility> {
+    const MAX: Self = Some(EffectiveVisibility::from_vis(ty::Visibility::Public));
     // Type inference is very smart sometimes.
     // It can make an impl reachable even some components of its type or trait are unreachable.
     // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
@@ -388,7 +389,13 @@ impl VisibilityLike for Option<Level> {
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
-        cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
+        if let Some(min) = find.min {
+            return find
+                .effective_visibilities
+                .effective_vis(def_id)
+                .map(|eff_vis| min.min(*eff_vis, find.tcx));
+        }
+        None
     }
 }
 
@@ -414,49 +421,79 @@ struct EmbargoVisitor<'tcx> {
     ///     n::p::f()
     /// }
     macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
-    /// Previous visibility level; `None` means unreachable.
-    prev_level: Option<Level>,
     /// Has something changed in the level map?
     changed: bool,
 }
 
 struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
-    level: Option<Level>,
+    effective_vis: Option<EffectiveVisibility>,
     item_def_id: LocalDefId,
     ev: &'a mut EmbargoVisitor<'tcx>,
+    level: Level,
 }
 
 impl<'tcx> EmbargoVisitor<'tcx> {
-    fn get(&self, def_id: LocalDefId) -> Option<Level> {
-        self.effective_visibilities.public_at_level(def_id)
+    fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
+        self.effective_visibilities.effective_vis(def_id).copied()
     }
 
-    /// Updates node level and returns the updated level.
-    fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
-        let old_level = self.get(def_id);
-        // Visibility levels can only grow.
-        if level > old_level {
-            self.effective_visibilities.set_public_at_level(
-                def_id,
-                || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
-                level.unwrap(),
-            );
-            self.changed = true;
-            level
-        } else {
-            old_level
+    // Updates node effective visibility.
+    fn update(
+        &mut self,
+        def_id: LocalDefId,
+        inherited_effective_vis: Option<EffectiveVisibility>,
+        level: Level,
+    ) {
+        let nominal_vis = self.tcx.local_visibility(def_id);
+        self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
+    }
+
+    fn update_eff_vis(
+        &mut self,
+        def_id: LocalDefId,
+        inherited_effective_vis: Option<EffectiveVisibility>,
+        nominal_vis: Option<ty::Visibility>,
+        level: Level,
+    ) {
+        if let Some(inherited_effective_vis) = inherited_effective_vis {
+            let private_vis =
+                ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id));
+            if Some(private_vis) != nominal_vis {
+                self.changed |= self.effective_visibilities.update(
+                    def_id,
+                    nominal_vis,
+                    || private_vis,
+                    inherited_effective_vis,
+                    level,
+                    self.tcx,
+                );
+            }
         }
     }
 
     fn reach(
         &mut self,
         def_id: LocalDefId,
-        level: Option<Level>,
+        effective_vis: Option<EffectiveVisibility>,
     ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
         ReachEverythingInTheInterfaceVisitor {
-            level: cmp::min(level, Some(Level::Reachable)),
+            effective_vis,
             item_def_id: def_id,
             ev: self,
+            level: Level::Reachable,
+        }
+    }
+
+    fn reach_through_impl_trait(
+        &mut self,
+        def_id: LocalDefId,
+        effective_vis: Option<EffectiveVisibility>,
+    ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
+        ReachEverythingInTheInterfaceVisitor {
+            effective_vis,
+            item_def_id: def_id,
+            ev: self,
+            level: Level::ReachableThroughImplTrait,
         }
     }
 
@@ -477,16 +514,18 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             return;
         }
 
-        if self.get(local_def_id).is_none() {
+        if self.effective_visibilities.public_at_level(local_def_id).is_none() {
             return;
         }
 
         // Since we are starting from an externally visible module,
         // all the parents in the loop below are also guaranteed to be modules.
         let mut module_def_id = macro_module_def_id;
+        let macro_ev = self.get(local_def_id);
+        assert!(macro_ev.is_some());
         loop {
             let changed_reachability =
-                self.update_macro_reachable(module_def_id, macro_module_def_id);
+                self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
             if changed_reachability || module_def_id == CRATE_DEF_ID {
                 break;
             }
@@ -500,21 +539,33 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         &mut self,
         module_def_id: LocalDefId,
         defining_mod: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
     ) -> bool {
         if self.macro_reachable.insert((module_def_id, defining_mod)) {
-            self.update_macro_reachable_mod(module_def_id, defining_mod);
+            self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev);
             true
         } else {
             false
         }
     }
 
-    fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
+    fn update_macro_reachable_mod(
+        &mut self,
+        module_def_id: LocalDefId,
+        defining_mod: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
+    ) {
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
             let def_kind = self.tcx.def_kind(item_id.owner_id);
             let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
-            self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
+            self.update_macro_reachable_def(
+                item_id.owner_id.def_id,
+                def_kind,
+                vis,
+                defining_mod,
+                macro_ev,
+            );
         }
         for child in self.tcx.module_children_local(module_def_id) {
             // FIXME: Use module children for the logic above too.
@@ -523,7 +574,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                 && let Res::Def(def_kind, def_id) = child.res
                 && let Some(def_id) = def_id.as_local() {
                 let vis = self.tcx.local_visibility(def_id);
-                self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
+                self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
             }
         }
     }
@@ -534,16 +585,14 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         def_kind: DefKind,
         vis: ty::Visibility,
         module: LocalDefId,
+        macro_ev: Option<EffectiveVisibility>,
     ) {
-        let level = Some(Level::Reachable);
-        if vis.is_public() {
-            self.update(def_id, level);
-        }
+        self.update(def_id, macro_ev, Level::Reachable);
         match def_kind {
             // No type privacy, so can be directly marked as reachable.
             DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
                 if vis.is_accessible_from(module, self.tcx) {
-                    self.update(def_id, level);
+                    self.update(def_id, macro_ev, Level::Reachable);
                 }
             }
 
@@ -555,7 +604,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
                 let item = self.tcx.hir().expect_item(def_id);
                 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
                     if vis.is_accessible_from(module, self.tcx) {
-                        self.update(def_id, level);
+                        self.update(def_id, macro_ev, Level::Reachable);
                     }
                 }
             }
@@ -566,26 +615,24 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             // the module, however may be reachable.
             DefKind::Mod => {
                 if vis.is_accessible_from(module, self.tcx) {
-                    self.update_macro_reachable(def_id, module);
+                    self.update_macro_reachable(def_id, module, macro_ev);
                 }
             }
 
             DefKind::Struct | DefKind::Union => {
                 // While structs and unions have type privacy, their fields do not.
-                if vis.is_public() {
-                    let item = self.tcx.hir().expect_item(def_id);
-                    if let hir::ItemKind::Struct(ref struct_def, _)
-                    | hir::ItemKind::Union(ref struct_def, _) = item.kind
-                    {
-                        for field in struct_def.fields() {
-                            let field_vis = self.tcx.local_visibility(field.def_id);
-                            if field_vis.is_accessible_from(module, self.tcx) {
-                                self.reach(field.def_id, level).ty();
-                            }
+                let item = self.tcx.hir().expect_item(def_id);
+                if let hir::ItemKind::Struct(ref struct_def, _)
+                | hir::ItemKind::Union(ref struct_def, _) = item.kind
+                {
+                    for field in struct_def.fields() {
+                        let field_vis = self.tcx.local_visibility(field.def_id);
+                        if field_vis.is_accessible_from(module, self.tcx) {
+                            self.reach(field.def_id, macro_ev).ty();
                         }
-                    } else {
-                        bug!("item {:?} with DefKind {:?}", item, def_kind);
                     }
+                } else {
+                    bug!("item {:?} with DefKind {:?}", item, def_kind);
                 }
             }
 
@@ -629,14 +676,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let item_level = match item.kind {
+        let item_ev = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                let impl_level = Option::<Level>::of_impl(
+                let impl_ev = Option::<EffectiveVisibility>::of_impl(
                     item.owner_id.def_id,
                     self.tcx,
                     &self.effective_visibilities,
                 );
-                self.update(item.owner_id.def_id, impl_level)
+
+                self.update_eff_vis(item.owner_id.def_id, impl_ev, None, Level::Direct);
+                impl_ev
             }
             _ => self.get(item.owner_id.def_id),
         };
@@ -645,38 +694,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in def.variants {
-                    let variant_level = self.update(variant.def_id, item_level);
+                    self.update(variant.def_id, item_ev, Level::Reachable);
+                    let variant_ev = self.get(variant.def_id);
                     if let Some(ctor_def_id) = variant.data.ctor_def_id() {
-                        self.update(ctor_def_id, item_level);
+                        self.update(ctor_def_id, variant_ev, Level::Reachable);
                     }
                     for field in variant.data.fields() {
-                        self.update(field.def_id, variant_level);
+                        self.update(field.def_id, variant_ev, Level::Reachable);
                     }
                 }
             }
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
-                    if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
-                    {
-                        self.update(impl_item_ref.id.owner_id.def_id, item_level);
-                    }
+                    self.update(impl_item_ref.id.owner_id.def_id, item_ev, Level::Direct);
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
-                    self.update(trait_item_ref.id.owner_id.def_id, item_level);
+                    self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
                 if let Some(ctor_def_id) = def.ctor_def_id() {
-                    self.update(ctor_def_id, item_level);
+                    self.update(ctor_def_id, item_ev, Level::Reachable);
                 }
                 for field in def.fields() {
-                    let vis = self.tcx.visibility(field.def_id);
-                    if vis.is_public() {
-                        self.update(field.def_id, item_level);
-                    }
+                    self.update(field.def_id, item_ev, Level::Reachable);
                 }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -684,9 +727,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
-                        self.update(foreign_item.id.owner_id.def_id, item_level);
-                    }
+                    self.update(foreign_item.id.owner_id.def_id, item_ev, Level::Reachable);
                 }
             }
 
@@ -721,8 +762,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // FIXME: This is some serious pessimization intended to workaround deficiencies
                     // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
                     // reachable if they are returned via `impl Trait`, even from private functions.
-                    let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
-                    self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
+                    let exist_ev = Some(EffectiveVisibility::from_vis(ty::Visibility::Public));
+                    self.reach_through_impl_trait(item.owner_id.def_id, exist_ev)
+                        .generics()
+                        .predicates()
+                        .ty();
                 }
             }
             // Visit everything.
@@ -730,17 +774,18 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
                         let tcx = self.tcx;
-                        let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
+                        let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
+
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
@@ -754,23 +799,24 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                 }
             }
             hir::ItemKind::TraitAlias(..) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                 }
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level)
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev)
                         .generics()
                         .predicates()
                         .ty()
                         .trait_ref();
 
                     for impl_item_ref in impl_.items {
-                        let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id);
-                        if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
+                        let impl_item_ev = self.get(impl_item_ref.id.owner_id.def_id);
+
+                        if impl_item_ev.is_some() {
+                            self.reach(impl_item_ref.id.owner_id.def_id, impl_item_ev)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -781,23 +827,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
 
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                 }
                 for variant in def.variants {
-                    let variant_level = self.get(variant.def_id);
-                    if variant_level.is_some() {
+                    let variant_ev = self.get(variant.def_id);
+                    if variant_ev.is_some() {
                         for field in variant.data.fields() {
-                            self.reach(field.def_id, variant_level).ty();
+                            self.reach(field.def_id, variant_ev).ty();
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.reach(item.owner_id.def_id, variant_level).ty();
+                        self.reach(item.owner_id.def_id, variant_ev).ty();
                     }
                     if let Some(ctor_def_id) = variant.data.ctor_def_id() {
-                        let ctor_level = self.get(ctor_def_id);
-                        if ctor_level.is_some() {
-                            self.reach(item.owner_id.def_id, ctor_level).ty();
+                        let ctor_ev = self.get(ctor_def_id);
+                        if ctor_ev.is_some() {
+                            self.reach(item.owner_id.def_id, ctor_ev).ty();
                         }
                     }
                 }
@@ -805,9 +851,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
-                    if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
+                    let foreign_item_ev = self.get(foreign_item.id.owner_id.def_id);
+                    if foreign_item_ev.is_some() {
+                        self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
                             .generics()
                             .predicates()
                             .ty();
@@ -816,36 +862,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             // Visit everything except for private fields.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                if item_level.is_some() {
-                    self.reach(item.owner_id.def_id, item_level).generics().predicates();
+                if item_ev.is_some() {
+                    self.reach(item.owner_id.def_id, item_ev).generics().predicates();
                     for field in struct_def.fields() {
-                        let field_level = self.get(field.def_id);
-                        if field_level.is_some() {
-                            self.reach(field.def_id, field_level).ty();
+                        let field_ev = self.get(field.def_id);
+                        if field_ev.is_some() {
+                            self.reach(field.def_id, field_ev).ty();
                         }
                     }
                 }
                 if let Some(ctor_def_id) = struct_def.ctor_def_id() {
-                    let ctor_level = self.get(ctor_def_id);
-                    if ctor_level.is_some() {
-                        self.reach(item.owner_id.def_id, ctor_level).ty();
+                    let ctor_ev = self.get(ctor_def_id);
+                    if ctor_ev.is_some() {
+                        self.reach(item.owner_id.def_id, ctor_ev).ty();
                     }
                 }
             }
         }
 
-        let orig_level = mem::replace(&mut self.prev_level, item_level);
         intravisit::walk_item(self, item);
-        self.prev_level = orig_level;
     }
 
     fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
         // Blocks can have public items, for example impls, but they always
         // start as completely private regardless of publicity of a function,
         // constant, type, field, etc., in which this block resides.
-        let orig_level = mem::replace(&mut self.prev_level, None);
         intravisit::walk_block(self, b);
-        self.prev_level = orig_level;
     }
 }
 
@@ -899,11 +941,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
         _descr: &dyn fmt::Display,
     ) -> ControlFlow<Self::BreakTy> {
         if let Some(def_id) = def_id.as_local() {
-            if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
-                (self.tcx().visibility(def_id.to_def_id()), self.level)
-            {
-                self.ev.update(def_id, self.level);
-            }
+            self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level);
         }
         ControlFlow::Continue(())
     }
@@ -2131,7 +2169,6 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
         tcx,
         effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
         macro_reachable: Default::default(),
-        prev_level: Some(Level::Direct),
         changed: false,
     };
 
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 87067189a77..7393bdb388a 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -199,7 +199,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let tcx = self.r.tcx;
         self.changed |= self.import_effective_visibilities.update(
             binding,
-            nominal_vis,
+            Some(nominal_vis),
             || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)),
             inherited_eff_vis,
             parent_id.level(),
@@ -213,7 +213,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
         let tcx = self.r.tcx;
         self.changed |= self.def_effective_visibilities.update(
             def_id,
-            nominal_vis,
+            Some(nominal_vis),
             || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)),
             inherited_eff_vis,
             parent_id.level(),
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index c897275bee2..a8fe560d1a7 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -101,3 +101,5 @@ session_invalid_int_literal_width = invalid width `{$width}` for integer literal
     .help = valid widths are 8, 16, 32, 64 and 128
 
 session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+
+session_nul_in_c_str = null characters in C string literals are not supported
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index cfdba1120ec..d80cc0aa043 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -518,6 +518,12 @@ pub struct ExternEntry {
     /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
     /// suppress `unused-crate-dependencies` warnings.
     pub nounused_dep: bool,
+    /// If the extern entry is not referenced in the crate, force it to be resolved anyway.
+    ///
+    /// Allows a dependency satisfying, for instance, a missing panic handler to be injected
+    /// without modifying source:
+    /// `--extern force:extras=/path/to/lib/libstd.rlib`
+    pub force: bool,
 }
 
 #[derive(Clone, Debug)]
@@ -556,7 +562,13 @@ impl Externs {
 
 impl ExternEntry {
     fn new(location: ExternLocation) -> ExternEntry {
-        ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
+        ExternEntry {
+            location,
+            is_private_dep: false,
+            add_prelude: false,
+            nounused_dep: false,
+            force: false,
+        }
     }
 
     pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
@@ -1064,37 +1076,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
 
 /// The parsed `--check-cfg` options
 pub struct CheckCfg<T = String> {
-    /// The set of all `names()`, if None no name checking is performed
-    pub names_valid: Option<FxHashSet<T>>,
+    /// Is well known names activated
+    pub exhaustive_names: bool,
     /// Is well known values activated
-    pub well_known_values: bool,
-    /// The set of all `values()`
-    pub values_valid: FxHashMap<T, FxHashSet<T>>,
+    pub exhaustive_values: bool,
+    /// All the expected values for a config name
+    pub expecteds: FxHashMap<T, ExpectedValues<T>>,
 }
 
 impl<T> Default for CheckCfg<T> {
     fn default() -> Self {
         CheckCfg {
-            names_valid: Default::default(),
-            values_valid: Default::default(),
-            well_known_values: false,
+            exhaustive_names: false,
+            exhaustive_values: false,
+            expecteds: FxHashMap::default(),
         }
     }
 }
 
 impl<T> CheckCfg<T> {
-    fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
+    fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
         CheckCfg {
-            names_valid: self
-                .names_valid
-                .as_ref()
-                .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
-            values_valid: self
-                .values_valid
-                .iter()
-                .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
+            exhaustive_names: self.exhaustive_names,
+            exhaustive_values: self.exhaustive_values,
+            expecteds: self
+                .expecteds
+                .into_iter()
+                .map(|(name, values)| {
+                    (
+                        f(name),
+                        match values {
+                            ExpectedValues::Some(values) => ExpectedValues::Some(
+                                values.into_iter().map(|b| b.map(|b| f(b))).collect(),
+                            ),
+                            ExpectedValues::Any => ExpectedValues::Any,
+                        },
+                    )
+                })
                 .collect(),
-            well_known_values: self.well_known_values,
+        }
+    }
+}
+
+pub enum ExpectedValues<T> {
+    Some(FxHashSet<Option<T>>),
+    Any,
+}
+
+impl<T: Eq + Hash> ExpectedValues<T> {
+    fn insert(&mut self, value: T) -> bool {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
+            ExpectedValues::Any => false,
+        }
+    }
+}
+
+impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
+            ExpectedValues::Any => {}
+        }
+    }
+}
+
+impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
+    fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+        match self {
+            ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
+            ExpectedValues::Any => {}
         }
     }
 }
@@ -1103,58 +1154,27 @@ impl<T> CheckCfg<T> {
 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
 /// but the symbol interner is not yet set up then, so we must convert it later.
 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
-    cfg.map_data(|s| Symbol::intern(s))
+    cfg.map_data(|s| Symbol::intern(&s))
 }
 
 impl CrateCheckConfig {
-    /// Fills a `CrateCheckConfig` with well-known configuration names.
-    fn fill_well_known_names(&mut self) {
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_values`
-        const WELL_KNOWN_NAMES: &[Symbol] = &[
-            // rustc
-            sym::unix,
-            sym::windows,
-            sym::target_os,
-            sym::target_family,
-            sym::target_arch,
-            sym::target_endian,
-            sym::target_pointer_width,
-            sym::target_env,
-            sym::target_abi,
-            sym::target_vendor,
-            sym::target_thread_local,
-            sym::target_has_atomic_load_store,
-            sym::target_has_atomic,
-            sym::target_has_atomic_equal_alignment,
-            sym::target_feature,
-            sym::panic,
-            sym::sanitize,
-            sym::debug_assertions,
-            sym::proc_macro,
-            sym::test,
-            sym::feature,
-            // rustdoc
-            sym::doc,
-            sym::doctest,
-            // miri
-            sym::miri,
-        ];
-
-        // We only insert well-known names if `names()` was activated
-        if let Some(names_valid) = &mut self.names_valid {
-            names_valid.extend(WELL_KNOWN_NAMES);
-        }
-    }
-
-    /// Fills a `CrateCheckConfig` with well-known configuration values.
-    fn fill_well_known_values(&mut self, current_target: &Target) {
-        if !self.well_known_values {
+    pub fn fill_well_known(&mut self, current_target: &Target) {
+        if !self.exhaustive_values && !self.exhaustive_names {
             return;
         }
 
-        // NOTE: This should be kept in sync with `default_configuration` and
-        // `fill_well_known_names`
+        let no_values = || {
+            let mut values = FxHashSet::default();
+            values.insert(None);
+            ExpectedValues::Some(values)
+        };
+
+        let empty_values = || {
+            let values = FxHashSet::default();
+            ExpectedValues::Some(values)
+        };
+
+        // NOTE: This should be kept in sync with `default_configuration`
 
         let panic_values = &PanicStrategy::all();
 
@@ -1174,6 +1194,9 @@ impl CrateCheckConfig {
         // Unknown possible values:
         //  - `feature`
         //  - `target_feature`
+        for name in [sym::feature, sym::target_feature] {
+            self.expecteds.entry(name).or_insert(ExpectedValues::Any);
+        }
 
         // No-values
         for name in [
@@ -1187,20 +1210,23 @@ impl CrateCheckConfig {
             sym::debug_assertions,
             sym::target_thread_local,
         ] {
-            self.values_valid.entry(name).or_default();
+            self.expecteds.entry(name).or_insert_with(no_values);
         }
 
         // Pre-defined values
-        self.values_valid.entry(sym::panic).or_default().extend(panic_values);
-        self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
-        self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
-        self.values_valid
-            .entry(sym::target_has_atomic_load_store)
-            .or_default()
+        self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
+        self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
+        self.expecteds
+            .entry(sym::target_has_atomic)
+            .or_insert_with(no_values)
             .extend(atomic_values);
-        self.values_valid
+        self.expecteds
+            .entry(sym::target_has_atomic_load_store)
+            .or_insert_with(no_values)
+            .extend(atomic_values);
+        self.expecteds
             .entry(sym::target_has_atomic_equal_alignment)
-            .or_default()
+            .or_insert_with(no_values)
             .extend(atomic_values);
 
         // Target specific values
@@ -1218,47 +1244,50 @@ impl CrateCheckConfig {
 
             // Initialize (if not already initialized)
             for &e in VALUES {
-                self.values_valid.entry(e).or_default();
+                let entry = self.expecteds.entry(e);
+                if !self.exhaustive_values {
+                    entry.or_insert(ExpectedValues::Any);
+                } else {
+                    entry.or_insert_with(empty_values);
+                }
             }
 
-            // Get all values map at once otherwise it would be costly.
-            // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
-            let [
-                values_target_os,
-                values_target_family,
-                values_target_arch,
-                values_target_endian,
-                values_target_env,
-                values_target_abi,
-                values_target_vendor,
-                values_target_pointer_width,
-            ] = self
-                .values_valid
-                .get_many_mut(VALUES)
-                .expect("unable to get all the check-cfg values buckets");
+            if self.exhaustive_values {
+                // Get all values map at once otherwise it would be costly.
+                // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
+                let [
+                    values_target_os,
+                    values_target_family,
+                    values_target_arch,
+                    values_target_endian,
+                    values_target_env,
+                    values_target_abi,
+                    values_target_vendor,
+                    values_target_pointer_width,
+                ] = self
+                    .expecteds
+                    .get_many_mut(VALUES)
+                    .expect("unable to get all the check-cfg values buckets");
 
-            for target in TARGETS
-                .iter()
-                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
-                .chain(iter::once(current_target.clone()))
-            {
-                values_target_os.insert(Symbol::intern(&target.options.os));
-                values_target_family
-                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
-                values_target_arch.insert(Symbol::intern(&target.arch));
-                values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
-                values_target_env.insert(Symbol::intern(&target.options.env));
-                values_target_abi.insert(Symbol::intern(&target.options.abi));
-                values_target_vendor.insert(Symbol::intern(&target.options.vendor));
-                values_target_pointer_width.insert(sym::integer(target.pointer_width));
+                for target in TARGETS
+                    .iter()
+                    .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+                    .chain(iter::once(current_target.clone()))
+                {
+                    values_target_os.insert(Symbol::intern(&target.options.os));
+                    values_target_family.extend(
+                        target.options.families.iter().map(|family| Symbol::intern(family)),
+                    );
+                    values_target_arch.insert(Symbol::intern(&target.arch));
+                    values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
+                    values_target_env.insert(Symbol::intern(&target.options.env));
+                    values_target_abi.insert(Symbol::intern(&target.options.abi));
+                    values_target_vendor.insert(Symbol::intern(&target.options.vendor));
+                    values_target_pointer_width.insert(sym::integer(target.pointer_width));
+                }
             }
         }
     }
-
-    pub fn fill_well_known(&mut self, current_target: &Target) {
-        self.fill_well_known_names();
-        self.fill_well_known_values(current_target);
-    }
 }
 
 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
@@ -2244,6 +2273,7 @@ pub fn parse_externs(
         let mut is_private_dep = false;
         let mut add_prelude = true;
         let mut nounused_dep = false;
+        let mut force = false;
         if let Some(opts) = options {
             if !is_unstable_enabled {
                 early_error(
@@ -2266,6 +2296,7 @@ pub fn parse_externs(
                         }
                     }
                     "nounused" => nounused_dep = true,
+                    "force" => force = true,
                     _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
                 }
             }
@@ -2276,6 +2307,8 @@ pub fn parse_externs(
         entry.is_private_dep |= is_private_dep;
         // likewise `nounused`
         entry.nounused_dep |= nounused_dep;
+        // and `force`
+        entry.force |= force;
         // If any flag is missing `noprelude`, then add to the prelude.
         entry.add_prelude |= add_prelude;
     }
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 0df62c2064e..546c0fa8e03 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_ast::token;
 use rustc_ast::util::literal::LitError;
 use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
 use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
+use rustc_span::{BytePos, Span, Symbol};
 use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
 
 #[derive(Diagnostic)]
@@ -323,6 +323,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(session_nul_in_c_str)]
+pub(crate) struct NulInCStr {
+    #[primary_span]
+    pub span: Span,
+}
+
 pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
     // Checks if `s` looks like i32 or u1234 etc.
     fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -401,6 +408,12 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             };
             sess.emit_err(IntLiteralTooLarge { span, limit });
         }
+        LitError::NulInCStr(range) => {
+            let lo = BytePos(span.lo().0 + range.start as u32 + 2);
+            let hi = BytePos(span.lo().0 + range.end as u32 + 2);
+            let span = span.with_lo(lo).with_hi(hi);
+            sess.emit_err(NulInCStr { span });
+        }
     }
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d9e191c00c9..243da98c3c2 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1235,6 +1235,8 @@ options! {
         line-tables-only, limited, or full; default: 0)"),
     default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
         "allow the linker to link its default libraries (default: no)"),
+    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "import library generation tool (ignored except when targeting windows-gnu)"),
     embed_bitcode: bool = (true, parse_bool, [TRACKED],
         "emit bitcode in rlibs (default: yes)"),
     extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -1391,8 +1393,6 @@ options! {
         (default: no)"),
     diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
         "set the current output width for diagnostic truncation"),
-    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
-        "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 341cc61fd1c..7bbab34c69a 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1744,6 +1744,28 @@ impl SourceFile {
         BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
     }
 
+    /// Calculates a normalized byte position from a byte offset relative to the
+    /// start of the file.
+    ///
+    /// When we get an inline assembler error from LLVM during codegen, we
+    /// import the expanded assembly code as a new `SourceFile`, which can then
+    /// be used for error reporting with spans. However the byte offsets given
+    /// to us by LLVM are relative to the start of the original buffer, not the
+    /// normalized one. Hence we need to convert those offsets to the normalized
+    /// form when constructing spans.
+    pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
+        let diff = match self
+            .normalized_pos
+            .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
+        {
+            Ok(i) => self.normalized_pos[i].diff,
+            Err(i) if i == 0 => 0,
+            Err(i) => self.normalized_pos[i - 1].diff,
+        };
+
+        BytePos::from_u32(self.start_pos.0 + offset - diff)
+    }
+
     /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
     pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
         // The number of extra bytes due to multibyte chars in the `SourceFile`.
@@ -2199,6 +2221,7 @@ pub struct ErrorGuaranteed(());
 impl ErrorGuaranteed {
     /// To be used only if you really know what you are doing... ideally, we would find a way to
     /// eliminate all calls to this method.
+    #[deprecated = "`Session::delay_span_bug` should be preferred over this function"]
     pub fn unchecked_claim_error_was_emitted() -> Self {
         ErrorGuaranteed(())
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1140a922f9f..b97ec6c684b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -441,6 +441,7 @@ symbols! {
         bridge,
         bswap,
         c_str,
+        c_str_literals,
         c_unwind,
         c_variadic,
         c_void,
@@ -1206,6 +1207,7 @@ symbols! {
         require,
         residual,
         result,
+        resume,
         return_position_impl_trait_in_trait,
         return_type_notation,
         rhs,
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 266691b2c88..705966f5237 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -839,6 +839,7 @@ pub enum InlineAsmClobberAbi {
     AArch64,
     AArch64NoX18,
     RiscV,
+    LoongArch,
 }
 
 impl InlineAsmClobberAbi {
@@ -880,6 +881,10 @@ impl InlineAsmClobberAbi {
                 "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
                 _ => Err(&["C", "system", "efiapi"]),
             },
+            InlineAsmArch::LoongArch64 => match name {
+                "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::LoongArch),
+                _ => Err(&["C", "system", "efiapi"]),
+            },
             _ => Err(&[]),
         }
     }
@@ -1022,6 +1027,21 @@ impl InlineAsmClobberAbi {
                     v24, v25, v26, v27, v28, v29, v30, v31,
                 }
             },
+            InlineAsmClobberAbi::LoongArch => clobbered_regs! {
+                LoongArch LoongArchInlineAsmReg {
+                    // ra
+                    r1,
+                    // a0-a7
+                    r4, r5, r6, r7, r8, r9, r10, r11,
+                    // t0-t8
+                    r12, r13, r14, r15, r16, r17, r18, r19, r20,
+                    // fa0-fa7
+                    f0, f1, f2, f3, f4, f5, f6, f7,
+                    // ft0-ft15
+                    f8, f9, f10, f11, f12, f13, f14, f15,
+                    f16, f17, f18, f19, f20, f21, f22, f23,
+                }
+            },
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
deleted file mode 100644
index 7e1dba4ed26..00000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::infer::InferCtxt;
-
-use rustc_infer::infer::ObligationEmittingRelation;
-use rustc_infer::traits::PredicateObligations;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct CollectAllMismatches<'a, 'tcx> {
-    pub infcx: &'a InferCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
-    pub errors: Vec<TypeError<'tcx>>,
-}
-
-impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
-    fn tag(&self) -> &'static str {
-        "CollectAllMismatches"
-    }
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn a_is_expected(&self) -> bool {
-        true
-    }
-
-    fn relate_with_variance<T: Relate<'tcx>>(
-        &mut self,
-        _: ty::Variance,
-        _: ty::VarianceDiagInfo<'tcx>,
-        a: T,
-        b: T,
-    ) -> RelateResult<'tcx, T> {
-        self.relate(a, b)
-    }
-
-    fn regions(
-        &mut self,
-        a: ty::Region<'tcx>,
-        _b: ty::Region<'tcx>,
-    ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        Ok(a)
-    }
-
-    fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-        self.infcx.probe(|_| {
-            if a.is_ty_var() || b.is_ty_var() {
-                Ok(a)
-            } else {
-                self.infcx.super_combine_tys(self, a, b).or_else(|e| {
-                    self.errors.push(e);
-                    Ok(a)
-                })
-            }
-        })
-    }
-
-    fn consts(
-        &mut self,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
-        self.infcx.probe(|_| {
-            if a.is_ct_infer() || b.is_ct_infer() {
-                Ok(a)
-            } else {
-                relate::super_relate_consts(self, a, b) // could do something similar here for constants!
-            }
-        })
-    }
-
-    fn binders<T: Relate<'tcx>>(
-        &mut self,
-        a: ty::Binder<'tcx, T>,
-        b: ty::Binder<'tcx, T>,
-    ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
-        Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
-    }
-}
-
-impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
-    fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
-        // FIXME(deferred_projection_equality): We really should get rid of this relation.
-        ty::AliasRelationDirection::Equate
-    }
-
-    fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
-        // FIXME(deferred_projection_equality)
-    }
-
-    fn register_predicates(
-        &mut self,
-        _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>,
-    ) {
-        // FIXME(deferred_projection_equality)
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 8f2a5d649f0..afb64da8b61 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,5 +1,4 @@
 mod ambiguity;
-pub mod method_chain;
 pub mod on_unimplemented;
 pub mod suggestions;
 
@@ -559,6 +558,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             suggest_increasing_limit,
             |err| {
                 self.note_obligation_cause_code(
+                    obligation.cause.body_id,
                     err,
                     predicate,
                     obligation.param_env,
@@ -1431,6 +1431,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 | ObligationCauseCode::ExprItemObligation(..) = code
                 {
                     self.note_obligation_cause_code(
+                        error.obligation.cause.body_id,
                         &mut diag,
                         error.obligation.predicate,
                         error.obligation.param_env,
@@ -2544,6 +2545,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
             self.note_obligation_cause_code(
+                obligation.cause.body_id,
                 err,
                 obligation.predicate,
                 obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index d34eb193453..53bf38c0a34 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -25,10 +25,9 @@ use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_hir::{Expr, HirId};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
 use rustc_middle::hir::map;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
-use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
@@ -39,9 +38,9 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
 use rustc_target::spec::abi;
+use std::iter;
 use std::ops::Deref;
 
-use super::method_chain::CollectAllMismatches;
 use super::InferCtxtPrivExt;
 use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -319,6 +318,7 @@ pub trait TypeErrCtxtExt<'tcx> {
 
     fn note_obligation_cause_code<T>(
         &self,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
         predicate: T,
         param_env: ty::ParamEnv<'tcx>,
@@ -359,8 +359,9 @@ pub trait TypeErrCtxtExt<'tcx> {
     );
     fn note_function_argument_obligation(
         &self,
-        arg_hir_id: HirId,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
+        arg_hir_id: HirId,
         parent_code: &ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         predicate: ty::Predicate<'tcx>,
@@ -2742,6 +2743,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // bound that introduced the obligation (e.g. `T: Send`).
         debug!(?next_code);
         self.note_obligation_cause_code(
+            obligation.cause.body_id,
             err,
             obligation.predicate,
             obligation.param_env,
@@ -2753,6 +2755,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
     fn note_obligation_cause_code<T>(
         &self,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
         predicate: T,
         param_env: ty::ParamEnv<'tcx>,
@@ -2790,7 +2793,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::LetElse
             | ObligationCauseCode::BinOp { .. }
             | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
-            | ObligationCauseCode::RustCall => {}
+            | ObligationCauseCode::RustCall
+            | ObligationCauseCode::DropImpl => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
@@ -3152,6 +3156,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     // #74711: avoid a stack overflow
                     ensure_sufficient_stack(|| {
                         self.note_obligation_cause_code(
+                            body_id,
                             err,
                             parent_predicate,
                             param_env,
@@ -3163,6 +3168,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 } else {
                     ensure_sufficient_stack(|| {
                         self.note_obligation_cause_code(
+                            body_id,
                             err,
                             parent_predicate,
                             param_env,
@@ -3292,6 +3298,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         parent_predicate,
                         param_env,
@@ -3307,6 +3314,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         parent_predicate,
                         param_env,
@@ -3323,8 +3331,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ..
             } => {
                 self.note_function_argument_obligation(
-                    arg_hir_id,
+                    body_id,
                     err,
+                    arg_hir_id,
                     parent_code,
                     param_env,
                     predicate,
@@ -3332,6 +3341,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 );
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
+                        body_id,
                         err,
                         predicate,
                         param_env,
@@ -3553,8 +3563,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     }
     fn note_function_argument_obligation(
         &self,
-        arg_hir_id: HirId,
+        body_id: LocalDefId,
         err: &mut Diagnostic,
+        arg_hir_id: HirId,
         parent_code: &ObligationCauseCode<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
         failed_pred: ty::Predicate<'tcx>,
@@ -3587,7 +3598,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             // to an associated type (as seen from `trait_pred`) in the predicate. Like in
             // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
             let mut type_diffs = vec![];
-
             if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
                 && let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
                 && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
@@ -3596,14 +3606,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
                 {
-                    let mut c = CollectAllMismatches {
-                        infcx: self.infcx,
-                        param_env,
-                        errors: vec![],
+                    let where_pred = self.instantiate_binder_with_placeholders(where_pred);
+                    let failed_pred = self.instantiate_binder_with_fresh_vars(
+                        expr.span,
+                        LateBoundRegionConversionTime::FnCall,
+                        failed_pred
+                    );
+
+                    let zipped =
+                        iter::zip(where_pred.trait_ref.substs, failed_pred.trait_ref.substs);
+                    for (expected, actual) in zipped {
+                        self.probe(|_| {
+                            match self
+                                .at(&ObligationCause::misc(expr.span, body_id), param_env)
+                                .eq(DefineOpaqueTypes::No, expected, actual)
+                            {
+                                Ok(_) => (), // We ignore nested obligations here for now.
+                                Err(err) => type_diffs.push(err),
+                            }
+                        })
                     };
-                    if let Ok(_) = c.relate(where_pred, failed_pred) {
-                        type_diffs = c.errors;
-                    }
                 } else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
                     && let Some(found) = failed_pred.skip_binder().term.ty()
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 8b8c50f6b83..d8e5725d3ca 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -62,7 +62,7 @@ pub use self::util::elaborate;
 pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{
-    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
+    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
     SupertraitDefIds,
 };
 
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index eedf459ce8f..b10aaad5f2a 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -177,15 +177,55 @@ fn resolve_associated_item<'tcx>(
 
             Some(ty::Instance::new(leaf_def.item.def_id, substs))
         }
-        traits::ImplSource::Generator(generator_data) => Some(Instance {
-            def: ty::InstanceDef::Item(generator_data.generator_def_id),
-            substs: generator_data.substs,
-        }),
-        traits::ImplSource::Future(future_data) => Some(Instance {
-            def: ty::InstanceDef::Item(future_data.generator_def_id),
-            substs: future_data.substs,
-        }),
+        traits::ImplSource::Generator(generator_data) => {
+            if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
+                // For compiler developers who'd like to add new items to `Generator`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(generator_data.generator_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in generator type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
+            Some(Instance {
+                def: ty::InstanceDef::Item(generator_data.generator_def_id),
+                substs: generator_data.substs,
+            })
+        }
+        traits::ImplSource::Future(future_data) => {
+            if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::poll {
+                // For compiler developers who'd like to add new items to `Future`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(future_data.generator_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in async generator type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
+            Some(Instance {
+                def: ty::InstanceDef::Item(future_data.generator_def_id),
+                substs: future_data.substs,
+            })
+        }
         traits::ImplSource::Closure(closure_data) => {
+            if cfg!(debug_assertions)
+                && ![sym::call, sym::call_mut, sym::call_once]
+                    .contains(&tcx.item_name(trait_item_id))
+            {
+                // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+                // you either need to generate a shim body, or perhaps return
+                // `InstanceDef::Item` pointing to a trait default method body if
+                // it is given a default implementation by the trait.
+                span_bug!(
+                    tcx.def_span(closure_data.closure_def_id),
+                    "no definition for `{trait_ref}::{}` for built-in closure type",
+                    tcx.item_name(trait_item_id)
+                )
+            }
             let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
             Instance::resolve_closure(
                 tcx,
@@ -195,11 +235,29 @@ fn resolve_associated_item<'tcx>(
             )
         }
         traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
-            ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
-                def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
-                substs: rcvr_substs,
-            }),
-            _ => None,
+            ty::FnDef(..) | ty::FnPtr(..) => {
+                if cfg!(debug_assertions)
+                    && ![sym::call, sym::call_mut, sym::call_once]
+                        .contains(&tcx.item_name(trait_item_id))
+                {
+                    // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+                    // you either need to generate a shim body, or perhaps return
+                    // `InstanceDef::Item` pointing to a trait default method body if
+                    // it is given a default implementation by the trait.
+                    bug!(
+                        "no definition for `{trait_ref}::{}` for built-in fn type",
+                        tcx.item_name(trait_item_id)
+                    )
+                }
+                Some(Instance {
+                    def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
+                    substs: rcvr_substs,
+                })
+            }
+            _ => bug!(
+                "no built-in definition for `{trait_ref}::{}` for non-fn type",
+                tcx.item_name(trait_item_id)
+            ),
         },
         traits::ImplSource::Object(ref data) => {
             traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index ed513cb3c7f..c4a4cda6801 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty::{
 };
 use rustc_target::abi::*;
 
-use std::cmp;
+use std::assert_matches::assert_matches;
 
 /// Enforce some basic invariants on layouts.
 pub(super) fn sanity_check_layout<'tcx>(
@@ -68,21 +68,31 @@ pub(super) fn sanity_check_layout<'tcx>(
     }
 
     fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
+        // Verify the ABI mandated alignment and size.
+        let align = layout.abi.inherent_align(cx).map(|align| align.abi);
+        let size = layout.abi.inherent_size(cx);
+        let Some((align, size)) = align.zip(size) else {
+            assert_matches!(
+                layout.layout.abi(),
+                Abi::Uninhabited | Abi::Aggregate { .. },
+                "ABI unexpectedly missing alignment and/or size in {layout:#?}"
+            );
+            return
+        };
+        assert_eq!(
+            layout.layout.align().abi,
+            align,
+            "alignment mismatch between ABI and layout in {layout:#?}"
+        );
+        assert_eq!(
+            layout.layout.size(),
+            size,
+            "size mismatch between ABI and layout in {layout:#?}"
+        );
+
+        // Verify per-ABI invariants
         match layout.layout.abi() {
-            Abi::Scalar(scalar) => {
-                // No padding in scalars.
-                let size = scalar.size(cx);
-                let align = scalar.align(cx).abi;
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}"
-                );
+            Abi::Scalar(_) => {
                 // Check that this matches the underlying field.
                 let inner = skip_newtypes(cx, layout);
                 assert!(
@@ -135,24 +145,6 @@ pub(super) fn sanity_check_layout<'tcx>(
                 }
             }
             Abi::ScalarPair(scalar1, scalar2) => {
-                // Sanity-check scalar pairs. Computing the expected size and alignment is a bit of work.
-                let size1 = scalar1.size(cx);
-                let align1 = scalar1.align(cx).abi;
-                let size2 = scalar2.size(cx);
-                let align2 = scalar2.align(cx).abi;
-                let align = cmp::max(align1, align2);
-                let field2_offset = size1.align_to(align2);
-                let size = (field2_offset + size2).align_to(align);
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}",
-                );
                 // Check that the underlying pair of fields matches.
                 let inner = skip_newtypes(cx, layout);
                 assert!(
@@ -189,8 +181,9 @@ pub(super) fn sanity_check_layout<'tcx>(
                         "`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}"
                     )
                 });
-                assert!(
-                    fields.next().is_none(),
+                assert_matches!(
+                    fields.next(),
+                    None,
                     "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
                 );
                 // The fields might be in opposite order.
@@ -200,6 +193,10 @@ pub(super) fn sanity_check_layout<'tcx>(
                     (offset2, field2, offset1, field1)
                 };
                 // The fields should be at the right offset, and match the `scalar` layout.
+                let size1 = scalar1.size(cx);
+                let align1 = scalar1.align(cx).abi;
+                let size2 = scalar2.size(cx);
+                let align2 = scalar2.align(cx).abi;
                 assert_eq!(
                     offset1,
                     Size::ZERO,
@@ -213,10 +210,12 @@ pub(super) fn sanity_check_layout<'tcx>(
                     field1.align.abi, align1,
                     "`ScalarPair` first field with bad align in {inner:#?}",
                 );
-                assert!(
-                    matches!(field1.abi, Abi::Scalar(_)),
+                assert_matches!(
+                    field1.abi,
+                    Abi::Scalar(_),
                     "`ScalarPair` first field with bad ABI in {inner:#?}",
                 );
+                let field2_offset = size1.align_to(align2);
                 assert_eq!(
                     offset2, field2_offset,
                     "`ScalarPair` second field at bad offset in {inner:#?}",
@@ -229,27 +228,14 @@ pub(super) fn sanity_check_layout<'tcx>(
                     field2.align.abi, align2,
                     "`ScalarPair` second field with bad align in {inner:#?}",
                 );
-                assert!(
-                    matches!(field2.abi, Abi::Scalar(_)),
+                assert_matches!(
+                    field2.abi,
+                    Abi::Scalar(_),
                     "`ScalarPair` second field with bad ABI in {inner:#?}",
                 );
             }
-            Abi::Vector { count, element } => {
-                // No padding in vectors, except possibly for trailing padding to make the size a multiple of align.
-                let size = element.size(cx) * count;
-                let align = cx.data_layout().vector_align(size).abi;
-                let size = size.align_to(align); // needed e.g. for vectors of size 3
+            Abi::Vector { element, .. } => {
                 assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
-                assert_eq!(
-                    layout.layout.size(),
-                    size,
-                    "size mismatch between ABI and layout in {layout:#?}"
-                );
-                assert_eq!(
-                    layout.layout.align().abi,
-                    align,
-                    "alignment mismatch between ABI and layout in {layout:#?}"
-                );
                 // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
             }
             Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 9d5a72a73cd..73a2f6af579 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(assert_matches)]
 #![feature(iterator_try_collect)]
 #![feature(let_chains)]
 #![feature(never_type)]
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index efbbc1c2331..2daef82d6f1 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -3079,8 +3079,8 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> {
                 unsafe { self.root.reborrow() }
                     .as_mut()?
                     .borrow_mut()
-                    .first_leaf_edge()
-                    .next_kv()
+                    .last_leaf_edge()
+                    .next_back_kv()
                     .ok()?
                     .into_kv_valmut()
             }
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index da00d83bdbb..7ecffe3eef2 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -8,6 +8,7 @@ use crate::testing::crash_test::{CrashTestDummy, Panic};
 use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
 use crate::testing::rng::DeterministicRng;
 use crate::vec::Vec;
+use core::assert_matches::assert_matches;
 use std::cmp::Ordering;
 use std::iter;
 use std::mem;
@@ -2448,3 +2449,21 @@ fn test_cursor_mut_insert_after_4() {
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
     cur.insert_after(4, 'd');
 }
+
+#[test]
+fn cursor_peek_prev_agrees_with_cursor_mut() {
+    let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]);
+
+    let cursor = map.lower_bound(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+
+    // Shadow names so the two parts of this test match.
+    let mut cursor = map.lower_bound_mut(Bound::Excluded(&3));
+    assert!(cursor.key().is_none());
+
+    let prev = cursor.peek_prev();
+    assert_matches!(prev, Some((&3, _)));
+}
diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs
index 6750d7c0711..3fea9a44049 100644
--- a/library/core/src/array/ascii.rs
+++ b/library/core/src/array/ascii.rs
@@ -4,10 +4,23 @@ use crate::ascii;
 impl<const N: usize> [u8; N] {
     /// Converts this array of bytes into a array of ASCII characters,
     /// or returns `None` if any of the characters is non-ASCII.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char)]
+    /// #![feature(const_option)]
+    ///
+    /// const HEX_DIGITS: [std::ascii::Char; 16] =
+    ///     *b"0123456789abcdef".as_ascii().unwrap();
+    ///
+    /// assert_eq!(HEX_DIGITS[1].as_str(), "1");
+    /// assert_eq!(HEX_DIGITS[10].as_str(), "a");
+    /// ```
     #[unstable(feature = "ascii_char", issue = "110998")]
     #[must_use]
     #[inline]
-    pub fn as_ascii(&self) -> Option<&[ascii::Char; N]> {
+    pub const fn as_ascii(&self) -> Option<&[ascii::Char; N]> {
         if self.is_ascii() {
             // SAFETY: Just checked that it's ASCII
             Some(unsafe { self.as_ascii_unchecked() })
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index bd2b2c36c43..07b11814f96 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -79,9 +79,9 @@ use crate::str;
 ///
 /// [str]: prim@str "str"
 #[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
 #[stable(feature = "core_c_str", since = "1.64.0")]
 #[rustc_has_incoherent_inherent_impls]
+#[cfg_attr(not(bootstrap), lang = "CStr")]
 // FIXME:
 // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
 // on `CStr` being layout-compatible with `[u8]`.
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 520ec9abcf0..2568aaf34f3 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -310,6 +310,7 @@ where
 /// Real logic of both `Flatten` and `FlatMap` which simply delegate to
 /// this type.
 #[derive(Clone, Debug)]
+#[unstable(feature = "trusted_len", issue = "37572")]
 struct FlattenCompat<I, U> {
     iter: Fuse<I>,
     frontiter: Option<U>,
@@ -463,6 +464,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 impl<I, U> Iterator for FlattenCompat<I, U>
 where
     I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -577,6 +579,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 impl<I, U> DoubleEndedIterator for FlattenCompat<I, U>
 where
     I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
@@ -646,6 +649,7 @@ where
     }
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter>
 where
@@ -653,6 +657,7 @@ where
 {
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter>
 where
@@ -660,6 +665,7 @@ where
 {
 }
 
+#[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, const N: usize, I, T> TrustedLen
     for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter>
 where
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index ed0c05a6863..3abf66dbe29 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -150,6 +150,7 @@
 #![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_slice_from_ref)]
 #![feature(const_slice_index)]
+#![feature(const_slice_is_ascii)]
 #![feature(const_slice_ptr_len)]
 #![feature(const_slice_split_at_mut)]
 #![feature(const_str_from_utf8_unchecked_mut)]
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 2588b7d2bef..d09a24b4b1d 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -1287,7 +1287,7 @@ impl<T, const N: usize> MaybeUninit<[T; N]> {
     #[inline]
     pub const fn transpose(self) -> [MaybeUninit<T>; N] {
         // SAFETY: T and MaybeUninit<T> have the same layout
-        unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+        unsafe { intrinsics::transmute_unchecked(self) }
     }
 }
 
@@ -1307,6 +1307,6 @@ impl<T, const N: usize> [MaybeUninit<T>; N] {
     #[inline]
     pub const fn transpose(self) -> MaybeUninit<[T; N]> {
         // SAFETY: T and MaybeUninit<T> have the same layout
-        unsafe { super::transmute_copy(&ManuallyDrop::new(self)) }
+        unsafe { intrinsics::transmute_unchecked(self) }
     }
 }
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index 2d48e271580..8396aecf947 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -122,6 +122,7 @@ impl SocketAddr {
     #[stable(feature = "ip_addr", since = "1.7.0")]
     #[must_use]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
         match ip {
             IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
@@ -142,6 +143,7 @@ impl SocketAddr {
     #[must_use]
     #[stable(feature = "ip_addr", since = "1.7.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn ip(&self) -> IpAddr {
         match *self {
             SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
@@ -161,6 +163,7 @@ impl SocketAddr {
     /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_ip(&mut self, new_ip: IpAddr) {
         // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
         match (self, new_ip) {
@@ -183,6 +186,7 @@ impl SocketAddr {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn port(&self) -> u16 {
         match *self {
             SocketAddr::V4(ref a) => a.port(),
@@ -202,6 +206,7 @@ impl SocketAddr {
     /// assert_eq!(socket.port(), 1025);
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_port(&mut self, new_port: u16) {
         match *self {
             SocketAddr::V4(ref mut a) => a.set_port(new_port),
@@ -227,6 +232,7 @@ impl SocketAddr {
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn is_ipv4(&self) -> bool {
         matches!(*self, SocketAddr::V4(_))
     }
@@ -249,6 +255,7 @@ impl SocketAddr {
     #[must_use]
     #[stable(feature = "sockaddr_checker", since = "1.16.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn is_ipv6(&self) -> bool {
         matches!(*self, SocketAddr::V6(_))
     }
@@ -269,6 +276,7 @@ impl SocketAddrV4 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
         SocketAddrV4 { ip, port }
     }
@@ -286,6 +294,7 @@ impl SocketAddrV4 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn ip(&self) -> &Ipv4Addr {
         &self.ip
     }
@@ -302,6 +311,7 @@ impl SocketAddrV4 {
     /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
         self.ip = new_ip;
     }
@@ -319,6 +329,7 @@ impl SocketAddrV4 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -335,6 +346,7 @@ impl SocketAddrV4 {
     /// assert_eq!(socket.port(), 4242);
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
@@ -360,6 +372,7 @@ impl SocketAddrV6 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
         SocketAddrV6 { ip, port, flowinfo, scope_id }
     }
@@ -377,6 +390,7 @@ impl SocketAddrV6 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn ip(&self) -> &Ipv6Addr {
         &self.ip
     }
@@ -393,6 +407,7 @@ impl SocketAddrV6 {
     /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
         self.ip = new_ip;
     }
@@ -410,6 +425,7 @@ impl SocketAddrV6 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn port(&self) -> u16 {
         self.port
     }
@@ -426,6 +442,7 @@ impl SocketAddrV6 {
     /// assert_eq!(socket.port(), 4242);
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
@@ -453,6 +470,7 @@ impl SocketAddrV6 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn flowinfo(&self) -> u32 {
         self.flowinfo
     }
@@ -471,6 +489,7 @@ impl SocketAddrV6 {
     /// assert_eq!(socket.flowinfo(), 56);
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.flowinfo = new_flowinfo;
     }
@@ -493,6 +512,7 @@ impl SocketAddrV6 {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "const_socketaddr", since = "1.69.0")]
+    #[inline]
     pub const fn scope_id(&self) -> u32 {
         self.scope_id
     }
@@ -511,6 +531,7 @@ impl SocketAddrV6 {
     /// assert_eq!(socket.scope_id(), 42);
     /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[inline]
     pub fn set_scope_id(&mut self, new_scope_id: u32) {
         self.scope_id = new_scope_id;
     }
@@ -519,6 +540,7 @@ impl SocketAddrV6 {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV4> for SocketAddr {
     /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+    #[inline]
     fn from(sock4: SocketAddrV4) -> SocketAddr {
         SocketAddr::V4(sock4)
     }
@@ -527,6 +549,7 @@ impl From<SocketAddrV4> for SocketAddr {
 #[stable(feature = "ip_from_ip", since = "1.16.0")]
 impl From<SocketAddrV6> for SocketAddr {
     /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+    #[inline]
     fn from(sock6: SocketAddrV6) -> SocketAddr {
         SocketAddr::V6(sock6)
     }
@@ -624,6 +647,7 @@ impl fmt::Debug for SocketAddrV6 {
 
 #[stable(feature = "socketaddr_ordering", since = "1.45.0")]
 impl PartialOrd for SocketAddrV4 {
+    #[inline]
     fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
         Some(self.cmp(other))
     }
@@ -631,6 +655,7 @@ impl PartialOrd for SocketAddrV4 {
 
 #[stable(feature = "socketaddr_ordering", since = "1.45.0")]
 impl PartialOrd for SocketAddrV6 {
+    #[inline]
     fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
         Some(self.cmp(other))
     }
@@ -638,6 +663,7 @@ impl PartialOrd for SocketAddrV6 {
 
 #[stable(feature = "socketaddr_ordering", since = "1.45.0")]
 impl Ord for SocketAddrV4 {
+    #[inline]
     fn cmp(&self, other: &SocketAddrV4) -> Ordering {
         self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
     }
@@ -645,6 +671,7 @@ impl Ord for SocketAddrV4 {
 
 #[stable(feature = "socketaddr_ordering", since = "1.45.0")]
 impl Ord for SocketAddrV6 {
+    #[inline]
     fn cmp(&self, other: &SocketAddrV6) -> Ordering {
         self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
     }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index c38c68e1d58..ec1ef3cf43d 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1641,10 +1641,8 @@ impl<T> Option<T> {
     where
         F: FnOnce() -> T,
     {
-        if let None = *self {
-            // the compiler isn't smart enough to know that we are not dropping a `T`
-            // here and wants us to ensure `T` can be dropped at compile time.
-            mem::forget(mem::replace(self, Some(f())))
+        if let None = self {
+            *self = Some(f());
         }
 
         // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 7bae6692ad4..f3311f76a7f 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -10,9 +10,10 @@ use crate::ops;
 impl [u8] {
     /// Checks if all bytes in this slice are within the ASCII range.
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")]
     #[must_use]
     #[inline]
-    pub fn is_ascii(&self) -> bool {
+    pub const fn is_ascii(&self) -> bool {
         is_ascii(self)
     }
 
@@ -21,7 +22,7 @@ impl [u8] {
     #[unstable(feature = "ascii_char", issue = "110998")]
     #[must_use]
     #[inline]
-    pub fn as_ascii(&self) -> Option<&[ascii::Char]> {
+    pub const fn as_ascii(&self) -> Option<&[ascii::Char]> {
         if self.is_ascii() {
             // SAFETY: Just checked that it's ASCII
             Some(unsafe { self.as_ascii_unchecked() })
@@ -262,11 +263,29 @@ impl<'a> fmt::Debug for EscapeAscii<'a> {
 /// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
 /// from `../str/mod.rs`, which does something similar for utf8 validation.
 #[inline]
-fn contains_nonascii(v: usize) -> bool {
+const fn contains_nonascii(v: usize) -> bool {
     const NONASCII_MASK: usize = usize::repeat_u8(0x80);
     (NONASCII_MASK & v) != 0
 }
 
+/// ASCII test *without* the chunk-at-a-time optimizations.
+///
+/// This is carefully structured to produce nice small code -- it's smaller in
+/// `-O` than what the "obvious" ways produces under `-C opt-level=s`.  If you
+/// touch it, be sure to run (and update if needed) the assembly test.
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
+#[inline]
+pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
+    while let [rest @ .., last] = bytes {
+        if !last.is_ascii() {
+            break;
+        }
+        bytes = rest;
+    }
+    bytes.is_empty()
+}
+
 /// Optimized ASCII test that will use usize-at-a-time operations instead of
 /// byte-at-a-time operations (when possible).
 ///
@@ -280,7 +299,7 @@ fn contains_nonascii(v: usize) -> bool {
 /// If any of these loads produces something for which `contains_nonascii`
 /// (above) returns true, then we know the answer is false.
 #[inline]
-fn is_ascii(s: &[u8]) -> bool {
+const fn is_ascii(s: &[u8]) -> bool {
     const USIZE_SIZE: usize = mem::size_of::<usize>();
 
     let len = s.len();
@@ -292,7 +311,7 @@ fn is_ascii(s: &[u8]) -> bool {
     // We also do this for architectures where `size_of::<usize>()` isn't
     // sufficient alignment for `usize`, because it's a weird edge case.
     if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
-        return s.iter().all(|b| b.is_ascii());
+        return is_ascii_simple(s);
     }
 
     // We always read the first word unaligned, which means `align_offset` is
@@ -321,18 +340,26 @@ fn is_ascii(s: &[u8]) -> bool {
     // Paranoia check about alignment, since we're about to do a bunch of
     // unaligned loads. In practice this should be impossible barring a bug in
     // `align_offset` though.
-    debug_assert_eq!(word_ptr.addr() % mem::align_of::<usize>(), 0);
+    // While this method is allowed to spuriously fail in CTFE, if it doesn't
+    // have alignment information it should have given a `usize::MAX` for
+    // `align_offset` earlier, sending things through the scalar path instead of
+    // this one, so this check should pass if it's reachable.
+    debug_assert!(word_ptr.is_aligned_to(mem::align_of::<usize>()));
 
     // Read subsequent words until the last aligned word, excluding the last
     // aligned word by itself to be done in tail check later, to ensure that
     // tail is always one `usize` at most to extra branch `byte_pos == len`.
     while byte_pos < len - USIZE_SIZE {
-        debug_assert!(
-            // Sanity check that the read is in bounds
-            (word_ptr.addr() + USIZE_SIZE) <= start.addr().wrapping_add(len) &&
-            // And that our assumptions about `byte_pos` hold.
-            (word_ptr.addr() - start.addr()) == byte_pos
-        );
+        // Sanity check that the read is in bounds
+        debug_assert!(byte_pos + USIZE_SIZE <= len);
+        // And that our assumptions about `byte_pos` hold.
+        debug_assert!(matches!(
+            word_ptr.cast::<u8>().guaranteed_eq(start.wrapping_add(byte_pos)),
+            // These are from the same allocation, so will hopefully always be
+            // known to match even in CTFE, but if it refuses to compare them
+            // that's ok since it's just a debug check anyway.
+            None | Some(true),
+        ));
 
         // SAFETY: We know `word_ptr` is properly aligned (because of
         // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index d4981af90d1..4c891ba550f 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -44,6 +44,10 @@ mod raw;
 mod rotate;
 mod specialize;
 
+#[unstable(feature = "str_internals", issue = "none")]
+#[doc(hidden)]
+pub use ascii::is_ascii_simple;
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use iter::{Chunks, ChunksMut, Windows};
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 66fa9cf6f64..ef05b25fdd0 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2358,9 +2358,10 @@ impl str {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[rustc_const_unstable(feature = "const_slice_is_ascii", issue = "111090")]
     #[must_use]
     #[inline]
-    pub fn is_ascii(&self) -> bool {
+    pub const fn is_ascii(&self) -> bool {
         // We can treat each byte as character here: all multibyte characters
         // start with a byte that is not in the ASCII range, so we will stop
         // there already.
@@ -2372,7 +2373,7 @@ impl str {
     #[unstable(feature = "ascii_char", issue = "110998")]
     #[must_use]
     #[inline]
-    pub fn as_ascii(&self) -> Option<&[ascii::Char]> {
+    pub const fn as_ascii(&self) -> Option<&[ascii::Char]> {
         // Like in `is_ascii`, we can work on the bytes directly.
         self.as_bytes().as_ascii()
     }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 2a8403c85a4..172e5fccb61 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,6 @@
 // See src/libstd/primitive_docs.rs for documentation.
 
 use crate::cmp::Ordering::{self, *};
-use crate::mem::transmute;
 
 // Recursive macro for implementing n-ary tuple functions and operations
 //
@@ -142,16 +141,13 @@ macro_rules! maybe_tuple_doc {
 #[inline]
 const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
     // FIXME: Just use `==` once that's const-stable on `Option`s.
-    // This isn't using `match` because that optimizes worse due to
-    // making a two-step check (`Some` *then* the inner value).
-
-    // SAFETY: There's no public guarantee for `Option<Ordering>`,
-    // but we're core so we know that it's definitely a byte.
-    unsafe {
-        let c: i8 = transmute(c);
-        let x: i8 = transmute(Some(x));
-        c == x
-    }
+    // This is mapping `None` to 2 and then doing the comparison afterwards
+    // because it optimizes better (`None::<Ordering>` is represented as 2).
+    x as i8
+        == match c {
+            Some(c) => c as i8,
+            None => 2,
+        }
 }
 
 // Constructs an expression that performs a lexical ordering using method `$rel`.
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 54b11c543f1..caecda1bc63 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -337,6 +337,8 @@ pub enum LitKind {
     StrRaw(u8),
     ByteStr,
     ByteStrRaw(u8),
+    CStr,
+    CStrRaw(u8),
     Err,
 }
 
@@ -350,6 +352,8 @@ rpc_encode_decode!(
         StrRaw(n),
         ByteStr,
         ByteStrRaw(n),
+        CStr,
+        CStrRaw(n),
         Err,
     }
 );
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index 32ddc4346ee..5440d85df4a 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -40,11 +40,7 @@ impl Timespec {
     }
 
     fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -57,11 +53,7 @@ impl Timespec {
     }
 
     fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `libc::time_t`
-            .ok()
-            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
diff --git a/library/std/src/sys/sgx/abi/entry.S b/library/std/src/sys/sgx/abi/entry.S
index ca79d1d796e..8a063b65dac 100644
--- a/library/std/src/sys/sgx/abi/entry.S
+++ b/library/std/src/sys/sgx/abi/entry.S
@@ -26,7 +26,7 @@ IMAGE_BASE:
 .Lxsave_clear:
 .org .+24
 .Lxsave_mxcsr:
-    .short 0x1f80
+    .short 0x1fbf
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
@@ -178,6 +178,7 @@ sgx_entry:
     mov $-1, %rax
     mov $-1, %rdx
     xrstor .Lxsave_clear(%rip)
+    lfence
     mov %r10, %rdx
 
 /*  check if returning from usercall */
@@ -311,6 +312,9 @@ usercall:
     movq $0,%gs:tcsls_last_rsp
 /*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
+    /* MCDT mitigation requires an lfence after ldmxcsr _before_ any of the affected  */
+    /* vector instructions is used. We omit the lfence here as one is required before */
+    /* the jmp instruction anyway. */
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
     add $8, %rsp
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
index ce31cb45a69..f83f1644fe8 100644
--- a/library/std/src/sys/solid/time.rs
+++ b/library/std/src/sys/solid/time.rs
@@ -47,10 +47,10 @@ impl SystemTime {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?))
+        Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
     }
 }
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 15070b1f6a7..7307d9b2c86 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -326,6 +326,25 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
             use crate::ptr;
 
+            #[cfg(target_os = "freebsd")]
+            {
+                let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
+                unsafe {
+                    if libc::cpuset_getaffinity(
+                        libc::CPU_LEVEL_WHICH,
+                        libc::CPU_WHICH_PID,
+                        -1,
+                        mem::size_of::<libc::cpuset_t>(),
+                        &mut set,
+                    ) == 0 {
+                        let count = libc::CPU_COUNT(&set) as usize;
+                        if count > 0 {
+                            return Ok(NonZeroUsize::new_unchecked(count));
+                        }
+                    }
+                }
+            }
+
             let mut cpus: libc::c_uint = 0;
             let mut cpus_size = crate::mem::size_of_val(&cpus);
 
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index a61d926ca8b..a9fbc7ab108 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -113,11 +113,7 @@ impl Timespec {
     }
 
     pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_add(secs))?;
+        let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
@@ -126,15 +122,11 @@ impl Timespec {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
-        let mut secs = other
-            .as_secs()
-            .try_into() // <- target type would be `i64`
-            .ok()
-            .and_then(|secs| self.tv_sec.checked_sub(secs))?;
+        let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
         let mut nsec = self.tv_nsec.0 as i32 - other.subsec_nanos() as i32;
@@ -142,7 +134,7 @@ impl Timespec {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(Timespec::new(secs, nsec as i64))
+        Some(Timespec::new(secs, nsec.into()))
     }
 
     #[allow(dead_code)]
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 2e64ae59aff..6ed84806e6d 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -1,4 +1,5 @@
 use super::{Duration, Instant, SystemTime, UNIX_EPOCH};
+use core::fmt::Debug;
 #[cfg(not(target_arch = "wasm32"))]
 use test::{black_box, Bencher};
 
@@ -201,6 +202,32 @@ fn since_epoch() {
     assert!(a < hundred_twenty_years);
 }
 
+#[test]
+fn big_math() {
+    // Check that the same result occurs when adding/subtracting each duration one at a time as when
+    // adding/subtracting them all at once.
+    #[track_caller]
+    fn check<T: Eq + Copy + Debug>(start: Option<T>, op: impl Fn(&T, Duration) -> Option<T>) {
+        const DURATIONS: [Duration; 2] =
+            [Duration::from_secs(i64::MAX as _), Duration::from_secs(50)];
+        if let Some(start) = start {
+            assert_eq!(
+                op(&start, DURATIONS.into_iter().sum()),
+                DURATIONS.into_iter().try_fold(start, |t, d| op(&t, d))
+            )
+        }
+    }
+
+    check(SystemTime::UNIX_EPOCH.checked_sub(Duration::from_secs(100)), SystemTime::checked_add);
+    check(SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(100)), SystemTime::checked_sub);
+
+    let instant = Instant::now();
+    check(instant.checked_sub(Duration::from_secs(100)), Instant::checked_add);
+    check(instant.checked_sub(Duration::from_secs(i64::MAX as _)), Instant::checked_add);
+    check(instant.checked_add(Duration::from_secs(100)), Instant::checked_sub);
+    check(instant.checked_add(Duration::from_secs(i64::MAX as _)), Instant::checked_sub);
+}
+
 macro_rules! bench_instant_threaded {
     ($bench_name:ident, $thread_count:expr) => {
         #[bench]
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 19d67e80a61..dfe6bb7f057 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -11,6 +11,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "anstyle"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -38,10 +44,10 @@ version = "0.0.0"
 dependencies = [
  "build_helper",
  "cc",
+ "clap",
  "cmake",
  "fd-lock",
  "filetime",
- "getopts",
  "hex",
  "ignore",
  "is-terminal",
@@ -91,6 +97,46 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "clap"
+version = "4.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "956ac1f6381d8d82ab4684768f89c0ea3afe66925ceadb4eeb3fc452ffc55d62"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+ "once_cell",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84080e799e54cff944f4b4a4b0e71630b0e0443b25b985175c7dddc1a859b749"
+dependencies = [
+ "anstyle",
+ "bitflags",
+ "clap_lex",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.15",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+
 [[package]]
 name = "cmake"
 version = "0.1.48"
@@ -175,7 +221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
 dependencies = [
  "quote",
- "syn",
+ "syn 1.0.102",
 ]
 
 [[package]]
@@ -260,15 +306,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "getopts"
-version = "0.2.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
-dependencies = [
- "unicode-width",
-]
-
 [[package]]
 name = "globset"
 version = "0.4.8"
@@ -282,6 +319,12 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.19"
@@ -486,18 +529,18 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.46"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.18"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
 dependencies = [
  "proc-macro2",
 ]
@@ -606,7 +649,7 @@ checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 1.0.102",
 ]
 
 [[package]]
@@ -642,6 +685,17 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "syn"
+version = "2.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "sysinfo"
 version = "0.26.7"
@@ -707,12 +761,6 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
 
-[[package]]
-name = "unicode-width"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
-
 [[package]]
 name = "version_check"
 version = "0.9.4"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 7b9eaceb00f..fd5eb740630 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -34,7 +34,6 @@ is-terminal = "0.4"
 build_helper = { path = "../tools/build_helper" }
 cmake = "0.1.38"
 filetime = "0.2"
-getopts = "0.2.19"
 cc = "1.0.69"
 libc = "0.2"
 hex = "0.4"
@@ -56,6 +55,7 @@ walkdir = "2"
 
 # Dependencies needed by the build-metrics feature
 sysinfo = { version = "0.26.0", optional = true }
+clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
 
 # Solaris doesn't support flock() and thus fd-lock is not option now
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
@@ -86,6 +86,7 @@ build-metrics = ["sysinfo"]
 # dependencies, only bootstrap itself.
 [profile.dev]
 debug = 0
+
 [profile.dev.package]
 # Only use debuginfo=1 to further reduce compile times.
 bootstrap.debug = 1
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index d9d4685dfc7..1267c0be719 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -33,6 +33,7 @@ pub use crate::Compiler;
 // - use std::lazy for `Lazy`
 // - use std::cell for `OnceCell`
 // Once they get stabilized and reach beta.
+use clap::ValueEnum;
 use once_cell::sync::{Lazy, OnceCell};
 
 pub struct Builder<'a> {
@@ -576,19 +577,24 @@ impl<'a> ShouldRun<'a> {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, ValueEnum)]
 pub enum Kind {
+    #[clap(alias = "b")]
     Build,
+    #[clap(alias = "c")]
     Check,
     Clippy,
     Fix,
     Format,
+    #[clap(alias = "t")]
     Test,
     Bench,
+    #[clap(alias = "d")]
     Doc,
     Clean,
     Dist,
     Install,
+    #[clap(alias = "r")]
     Run,
     Setup,
     Suggest,
@@ -887,18 +893,19 @@ impl<'a> Builder<'a> {
     }
 
     pub fn new(build: &Build) -> Builder<'_> {
+        let paths = &build.config.paths;
         let (kind, paths) = match build.config.cmd {
-            Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
-            Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
-            Subcommand::Clippy { ref paths, .. } => (Kind::Clippy, &paths[..]),
-            Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
-            Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
-            Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
-            Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
-            Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
-            Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
-            Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
-            Subcommand::Clean { ref paths, .. } => (Kind::Clean, &paths[..]),
+            Subcommand::Build => (Kind::Build, &paths[..]),
+            Subcommand::Check { .. } => (Kind::Check, &paths[..]),
+            Subcommand::Clippy { .. } => (Kind::Clippy, &paths[..]),
+            Subcommand::Fix => (Kind::Fix, &paths[..]),
+            Subcommand::Doc { .. } => (Kind::Doc, &paths[..]),
+            Subcommand::Test { .. } => (Kind::Test, &paths[..]),
+            Subcommand::Bench { .. } => (Kind::Bench, &paths[..]),
+            Subcommand::Dist => (Kind::Dist, &paths[..]),
+            Subcommand::Install => (Kind::Install, &paths[..]),
+            Subcommand::Run { .. } => (Kind::Run, &paths[..]),
+            Subcommand::Clean { .. } => (Kind::Clean, &paths[..]),
             Subcommand::Format { .. } => (Kind::Format, &[][..]),
             Subcommand::Suggest { .. } => (Kind::Suggest, &[][..]),
             Subcommand::Setup { profile: ref path } => (
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 72ac46b6bfd..c32fe59bbf0 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -236,7 +236,7 @@ mod defaults {
     fn doc_default() {
         let mut config = configure("doc", &["A"], &["A"]);
         config.compiler_docs = true;
-        config.cmd = Subcommand::Doc { paths: Vec::new(), open: false, json: false };
+        config.cmd = Subcommand::Doc { open: false, json: false };
         let mut cache = run_build(&[], config);
         let a = TargetSelection::from_user("A");
 
@@ -545,12 +545,13 @@ mod dist {
     fn test_with_no_doc_stage0() {
         let mut config = configure(&["A"], &["A"]);
         config.stage = 0;
+        config.paths = vec!["library/std".into()];
         config.cmd = Subcommand::Test {
-            paths: vec!["library/std".into()],
             test_args: vec![],
             rustc_args: vec![],
-            fail_fast: true,
-            doc_tests: DocTests::No,
+            no_fail_fast: false,
+            no_doc: true,
+            doc: false,
             bless: false,
             force_rerun: false,
             compare_mode: None,
@@ -558,6 +559,7 @@ mod dist {
             pass: None,
             run: None,
             only_modified: false,
+            skip: vec![],
         };
 
         let build = Build::new(config);
@@ -587,7 +589,7 @@ mod dist {
     fn doc_ci() {
         let mut config = configure(&["A"], &["A"]);
         config.compiler_docs = true;
-        config.cmd = Subcommand::Doc { paths: Vec::new(), open: false, json: false };
+        config.cmd = Subcommand::Doc { open: false, json: false };
         let build = Build::new(config);
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
@@ -616,11 +618,12 @@ mod dist {
         // Behavior of `x.py test` doing various documentation tests.
         let mut config = configure(&["A"], &["A"]);
         config.cmd = Subcommand::Test {
-            paths: vec![],
             test_args: vec![],
             rustc_args: vec![],
-            fail_fast: true,
-            doc_tests: DocTests::Yes,
+            no_fail_fast: false,
+            doc: true,
+            no_doc: false,
+            skip: vec![],
             bless: false,
             force_rerun: false,
             compare_mode: None,
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 956b82385f6..b11be96cefe 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -20,15 +20,7 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
         arr.iter().copied().map(String::from)
     }
 
-    if let Subcommand::Clippy {
-        fix,
-        clippy_lint_allow,
-        clippy_lint_deny,
-        clippy_lint_warn,
-        clippy_lint_forbid,
-        ..
-    } = &builder.config.cmd
-    {
+    if let Subcommand::Clippy { fix, allow, deny, warn, forbid, .. } = &builder.config.cmd {
         // disable the most spammy clippy lints
         let ignored_lints = vec![
             "many_single_char_names", // there are a lot in stdarch
@@ -53,10 +45,10 @@ fn args(builder: &Builder<'_>) -> Vec<String> {
         args.extend(strings(&["--", "--cap-lints", "warn"]));
         args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint)));
         let mut clippy_lint_levels: Vec<String> = Vec::new();
-        clippy_lint_allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
-        clippy_lint_deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
-        clippy_lint_warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
-        clippy_lint_forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
+        allow.iter().for_each(|v| clippy_lint_levels.push(format!("-A{}", v)));
+        deny.iter().for_each(|v| clippy_lint_levels.push(format!("-D{}", v)));
+        warn.iter().for_each(|v| clippy_lint_levels.push(format!("-W{}", v)));
+        forbid.iter().for_each(|v| clippy_lint_levels.push(format!("-F{}", v)));
         args.extend(clippy_lint_levels);
         args.extend(builder.config.free_args.clone());
         args
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index ac51dc51aeb..f4e97d7dfed 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -21,7 +21,7 @@ use crate::cache::{Interned, INTERNER};
 use crate::cc_detect::{ndk_compiler, Language};
 use crate::channel::{self, GitInfo};
 pub use crate::flags::Subcommand;
-use crate::flags::{Color, Flags};
+use crate::flags::{Color, Flags, Warnings};
 use crate::util::{exe, output, t};
 use once_cell::sync::OnceCell;
 use serde::{Deserialize, Deserializer};
@@ -237,6 +237,8 @@ pub struct Config {
     initial_rustfmt: RefCell<RustfmtState>,
     #[cfg(test)]
     pub initial_rustfmt: RefCell<RustfmtState>,
+
+    pub paths: Vec<PathBuf>,
 }
 
 #[derive(Default, Deserialize, Clone)]
@@ -376,6 +378,16 @@ pub struct TargetSelection {
     file: Option<Interned<String>>,
 }
 
+/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic
+#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct TargetSelectionList(Vec<TargetSelection>);
+
+pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> {
+    Ok(TargetSelectionList(
+        s.split(",").filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(),
+    ))
+}
+
 impl TargetSelection {
     pub fn from_user(selection: &str) -> Self {
         let path = Path::new(selection);
@@ -871,26 +883,24 @@ impl Config {
     }
 
     fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig) -> Config {
-        let flags = Flags::parse(&args);
+        let mut flags = Flags::parse(&args);
         let mut config = Config::default_opts();
 
         // Set flags.
+        config.paths = std::mem::take(&mut flags.paths);
         config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect();
         config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
         config.on_fail = flags.on_fail;
-        config.jobs = flags.jobs.map(threads_from_config);
+        config.jobs = Some(threads_from_config(flags.jobs as u32));
         config.cmd = flags.cmd;
         config.incremental = flags.incremental;
         config.dry_run = if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled };
         config.keep_stage = flags.keep_stage;
         config.keep_stage_std = flags.keep_stage_std;
         config.color = flags.color;
-        config.free_args = flags.free_args.clone().unwrap_or_default();
-        if let Some(value) = flags.deny_warnings {
-            config.deny_warnings = value;
-        }
+        config.free_args = std::mem::take(&mut flags.free_args);
         config.llvm_profile_use = flags.llvm_profile_use;
         config.llvm_profile_generate = flags.llvm_profile_generate;
         config.llvm_bolt_profile_generate = flags.llvm_bolt_profile_generate;
@@ -1021,14 +1031,14 @@ impl Config {
             config.out = dir;
         }
 
-        config.hosts = if let Some(arg_host) = flags.host {
+        config.hosts = if let Some(TargetSelectionList(arg_host)) = flags.host {
             arg_host
         } else if let Some(file_host) = build.host {
             file_host.iter().map(|h| TargetSelection::from_user(h)).collect()
         } else {
             vec![config.build]
         };
-        config.targets = if let Some(arg_target) = flags.target {
+        config.targets = if let Some(TargetSelectionList(arg_target)) = flags.target {
             arg_target
         } else if let Some(file_target) = build.target {
             file_target.iter().map(|h| TargetSelection::from_user(h)).collect()
@@ -1064,7 +1074,7 @@ impl Config {
         set(&mut config.print_step_rusage, build.print_step_rusage);
         set(&mut config.patch_binaries_for_nix, build.patch_binaries_for_nix);
 
-        config.verbose = cmp::max(config.verbose, flags.verbose);
+        config.verbose = cmp::max(config.verbose, flags.verbose as usize);
 
         if let Some(install) = toml.install {
             config.prefix = install.prefix.map(PathBuf::from);
@@ -1137,7 +1147,14 @@ impl Config {
             config.rustc_default_linker = rust.default_linker;
             config.musl_root = rust.musl_root.map(PathBuf::from);
             config.save_toolstates = rust.save_toolstates.map(PathBuf::from);
-            set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings));
+            set(
+                &mut config.deny_warnings,
+                match flags.warnings {
+                    Warnings::Deny => Some(true),
+                    Warnings::Warn => Some(false),
+                    Warnings::Default => rust.deny_warnings,
+                },
+            );
             set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
             set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
             config.rust_thin_lto_import_instr_limit = rust.thin_lto_import_instr_limit;
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
index 50569eb4f37..d913ca295e2 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/config/tests.rs
@@ -1,4 +1,5 @@
-use super::{Config, TomlConfig};
+use super::{Config, Flags, TomlConfig};
+use clap::CommandFactory;
 use std::{env, path::Path};
 
 fn toml(config: &str) -> impl '_ + Fn(&Path) -> TomlConfig {
@@ -88,3 +89,8 @@ fn detect_src_and_out() {
         test(parse("build.build-dir = \"/tmp\""), build_dir);
     }
 }
+
+#[test]
+fn clap_verify() {
+    Flags::command().debug_assert();
+}
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 2a0ebee9a6b..c79a1bf9563 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -5,724 +5,409 @@
 
 use std::path::PathBuf;
 
-use getopts::Options;
+use clap::{Parser, ValueEnum};
 
 use crate::builder::{Builder, Kind};
-use crate::config::{Config, TargetSelection};
+use crate::config::{target_selection_list, Config, TargetSelectionList};
 use crate::setup::Profile;
-use crate::util::t;
 use crate::{Build, DocTests};
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default, Debug, ValueEnum)]
 pub enum Color {
     Always,
     Never,
+    #[default]
     Auto,
 }
 
-impl Default for Color {
-    fn default() -> Self {
-        Self::Auto
-    }
-}
-
-impl std::str::FromStr for Color {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s.to_lowercase().as_str() {
-            "always" => Ok(Self::Always),
-            "never" => Ok(Self::Never),
-            "auto" => Ok(Self::Auto),
-            _ => Err(()),
-        }
-    }
+/// Whether to deny warnings, emit them as warnings, or use the default behavior
+#[derive(Copy, Clone, Default, Debug, ValueEnum)]
+pub enum Warnings {
+    Deny,
+    Warn,
+    #[default]
+    Default,
 }
 
 /// Deserialized version of all flags for this compile.
+#[derive(Debug, Parser)]
+#[clap(
+    override_usage = "x.py <subcommand> [options] [<paths>...]",
+    disable_help_subcommand(true),
+    about = "",
+    next_line_help(false)
+)]
 pub struct Flags {
-    pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
-    pub on_fail: Option<String>,
-    pub stage: Option<u32>,
-    pub keep_stage: Vec<u32>,
-    pub keep_stage_std: Vec<u32>,
-
-    pub host: Option<Vec<TargetSelection>>,
-    pub target: Option<Vec<TargetSelection>>,
-    pub config: Option<PathBuf>,
-    pub build_dir: Option<PathBuf>,
-    pub jobs: Option<u32>,
+    #[command(subcommand)]
     pub cmd: Subcommand,
-    pub incremental: bool,
-    pub exclude: Vec<PathBuf>,
-    pub include_default_paths: bool,
-    pub rustc_error_format: Option<String>,
-    pub json_output: bool,
-    pub dry_run: bool,
-    pub color: Color,
 
+    #[arg(global(true), short, long, action = clap::ArgAction::Count)]
+    /// use verbose output (-vv for very verbose)
+    pub verbose: u8, // each extra -v after the first is passed to Cargo
+    #[arg(global(true), short, long)]
+    /// use incremental compilation
+    pub incremental: bool,
+    #[arg(global(true), long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")]
+    /// TOML configuration file for build
+    pub config: Option<PathBuf>,
+    #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
+    /// Build directory, overrides `build.build-dir` in `config.toml`
+    pub build_dir: Option<PathBuf>,
+
+    #[arg(global(true), long, value_name = "BUILD")]
+    /// build target of the stage0 compiler
+    pub build: Option<String>,
+
+    #[arg(global(true), long, value_name = "HOST", value_parser = target_selection_list)]
+    /// host targets to build
+    pub host: Option<TargetSelectionList>,
+
+    #[arg(global(true), long, value_name = "TARGET", value_parser = target_selection_list)]
+    /// target targets to build
+    pub target: Option<TargetSelectionList>,
+
+    #[arg(global(true), long, value_name = "PATH")]
+    /// build paths to exclude
+    pub exclude: Vec<PathBuf>,
+    #[arg(global(true), long)]
+    /// include default paths in addition to the provided ones
+    pub include_default_paths: bool,
+
+    #[arg(global(true), long)]
+    pub rustc_error_format: Option<String>,
+
+    #[arg(global(true), long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")]
+    /// command to run on failure
+    pub on_fail: Option<String>,
+    #[arg(global(true), long)]
+    /// dry run; don't build anything
+    pub dry_run: bool,
+    #[arg(global(true), long, value_name = "N")]
+    /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the
+    /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)
+    pub stage: Option<u32>,
+
+    #[arg(global(true), long, value_name = "N")]
+    /// stage(s) to keep without recompiling
+    /// (pass multiple times to keep e.g., both stages 0 and 1)
+    pub keep_stage: Vec<u32>,
+    #[arg(global(true), long, value_name = "N")]
+    /// stage(s) of the standard library to keep without recompiling
+    /// (pass multiple times to keep e.g., both stages 0 and 1)
+    pub keep_stage_std: Vec<u32>,
+    #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
+    /// path to the root of the rust checkout
+    pub src: Option<PathBuf>,
+
+    #[arg(
+        global(true),
+        short,
+        long,
+        default_value_t = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get),
+        value_name = "JOBS"
+    )]
+    /// number of jobs to run in parallel
+    pub jobs: usize,
     // This overrides the deny-warnings configuration option,
     // which passes -Dwarnings to the compiler invocations.
-    //
-    // true => deny, false => warn
-    pub deny_warnings: Option<bool>,
+    #[arg(global(true), long)]
+    #[clap(value_enum, default_value_t=Warnings::Default, value_name = "deny|warn")]
+    /// if value is deny, will deny warnings
+    /// if value is warn, will emit warnings
+    /// otherwise, use the default configured behaviour
+    pub warnings: Warnings,
 
-    pub rust_profile_use: Option<String>,
+    #[arg(global(true), long, value_name = "FORMAT")]
+    /// rustc error format
+    pub error_format: Option<String>,
+    #[arg(global(true), long)]
+    /// use message-format=json
+    pub json_output: bool,
+
+    #[arg(global(true), long, value_name = "STYLE")]
+    #[clap(value_enum, default_value_t = Color::Auto)]
+    /// whether to use color in cargo and rustc output
+    pub color: Color,
+
+    /// whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml
+    #[arg(global(true), long, value_name = "VALUE")]
+    pub llvm_skip_rebuild: Option<bool>,
+    /// generate PGO profile with rustc build
+    #[arg(global(true), long, value_name = "PROFILE")]
     pub rust_profile_generate: Option<String>,
-
+    /// use PGO profile for rustc build
+    #[arg(global(true), long, value_name = "PROFILE")]
+    pub rust_profile_use: Option<String>,
+    /// use PGO profile for LLVM build
+    #[arg(global(true), long, value_name = "PROFILE")]
     pub llvm_profile_use: Option<String>,
     // LLVM doesn't support a custom location for generating profile
     // information.
     //
     // llvm_out/build/profiles/ is the location this writes to.
+    /// generate PGO profile with llvm built for rustc
+    #[arg(global(true), long)]
     pub llvm_profile_generate: bool,
+    /// generate BOLT profile for LLVM build
+    #[arg(global(true), long)]
     pub llvm_bolt_profile_generate: bool,
+    /// use BOLT profile for LLVM build
+    #[arg(global(true), long, value_name = "PROFILE")]
     pub llvm_bolt_profile_use: Option<String>,
-
-    /// Arguments appearing after `--` to be forwarded to tools,
-    /// e.g. `--fix-broken` or test arguments.
-    pub free_args: Option<Vec<String>>,
-}
-
-#[derive(Debug, Clone)]
-pub enum Subcommand {
-    Build {
-        paths: Vec<PathBuf>,
-    },
-    Check {
-        paths: Vec<PathBuf>,
-    },
-    Clippy {
-        fix: bool,
-        paths: Vec<PathBuf>,
-        clippy_lint_allow: Vec<String>,
-        clippy_lint_deny: Vec<String>,
-        clippy_lint_warn: Vec<String>,
-        clippy_lint_forbid: Vec<String>,
-    },
-    Fix {
-        paths: Vec<PathBuf>,
-    },
-    Format {
-        paths: Vec<PathBuf>,
-        check: bool,
-    },
-    Doc {
-        paths: Vec<PathBuf>,
-        open: bool,
-        json: bool,
-    },
-    Test {
-        paths: Vec<PathBuf>,
-        /// Whether to automatically update stderr/stdout files
-        bless: bool,
-        force_rerun: bool,
-        compare_mode: Option<String>,
-        pass: Option<String>,
-        run: Option<String>,
-        test_args: Vec<String>,
-        rustc_args: Vec<String>,
-        fail_fast: bool,
-        doc_tests: DocTests,
-        rustfix_coverage: bool,
-        only_modified: bool,
-    },
-    Bench {
-        paths: Vec<PathBuf>,
-        test_args: Vec<String>,
-    },
-    Clean {
-        paths: Vec<PathBuf>,
-        all: bool,
-    },
-    Dist {
-        paths: Vec<PathBuf>,
-    },
-    Install {
-        paths: Vec<PathBuf>,
-    },
-    Run {
-        paths: Vec<PathBuf>,
-        args: Vec<String>,
-    },
-    Setup {
-        profile: Option<PathBuf>,
-    },
-    Suggest {
-        run: bool,
-    },
-}
-
-impl Default for Subcommand {
-    fn default() -> Subcommand {
-        Subcommand::Build { paths: vec![PathBuf::from("nowhere")] }
-    }
+    #[arg(global(true))]
+    /// paths for the subcommand
+    pub paths: Vec<PathBuf>,
+    /// arguments passed to subcommands
+    #[arg(global(true), last(true), value_name = "ARGS")]
+    pub free_args: Vec<String>,
 }
 
 impl Flags {
-    pub fn parse(args: &[String]) -> Flags {
-        let (args, free_args) = if let Some(pos) = args.iter().position(|s| s == "--") {
-            let (args, free) = args.split_at(pos);
-            (args, Some(free[1..].to_vec()))
-        } else {
-            (args, None)
-        };
-        let mut subcommand_help = String::from(
-            "\
-Usage: x.py <subcommand> [options] [<paths>...]
-
-Subcommands:
-    build, b    Compile either the compiler or libraries
-    check, c    Compile either the compiler or libraries, using cargo check
-    clippy      Run clippy (uses rustup/cargo-installed clippy binary)
-    fix         Run cargo fix
-    fmt         Run rustfmt
-    test, t     Build and run some test suites
-    bench       Build and run some benchmarks
-    doc, d      Build documentation
-    clean       Clean out build directories
-    dist        Build distribution artifacts
-    install     Install distribution artifacts
-    run, r      Run tools contained in this repository
-    setup       Create a config.toml (making it easier to use `x.py` itself)
-    suggest     Suggest a subset of tests to run, based on modified files
-
-To learn more about a subcommand, run `./x.py <subcommand> -h`",
-        );
-
-        let mut opts = Options::new();
-        // Options common to all subcommands
-        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
-        opts.optflag("i", "incremental", "use incremental compilation");
-        opts.optopt("", "config", "TOML configuration file for build", "FILE");
-        opts.optopt(
-            "",
-            "build-dir",
-            "Build directory, overrides `build.build-dir` in `config.toml`",
-            "DIR",
-        );
-        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
-        opts.optmulti("", "host", "host targets to build", "HOST");
-        opts.optmulti("", "target", "target targets to build", "TARGET");
-        opts.optmulti("", "exclude", "build paths to exclude", "PATH");
-        opts.optflag(
-            "",
-            "include-default-paths",
-            "include default paths in addition to the provided ones",
-        );
-        opts.optopt("", "on-fail", "command to run on failure", "CMD");
-        opts.optflag("", "dry-run", "dry run; don't build anything");
-        opts.optopt(
-            "",
-            "stage",
-            "stage to build (indicates compiler to use/test, e.g., stage 0 uses the \
-             bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)",
-            "N",
-        );
-        opts.optmulti(
-            "",
-            "keep-stage",
-            "stage(s) to keep without recompiling \
-            (pass multiple times to keep e.g., both stages 0 and 1)",
-            "N",
-        );
-        opts.optmulti(
-            "",
-            "keep-stage-std",
-            "stage(s) of the standard library to keep without recompiling \
-            (pass multiple times to keep e.g., both stages 0 and 1)",
-            "N",
-        );
-        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
-        let j_msg = format!(
-            "number of jobs to run in parallel; \
-             defaults to {} (this host's logical CPU count)",
-            std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get)
-        );
-        opts.optopt("j", "jobs", &j_msg, "JOBS");
-        opts.optflag("h", "help", "print this help message");
-        opts.optopt(
-            "",
-            "warnings",
-            "if value is deny, will deny warnings, otherwise use default",
-            "VALUE",
-        );
-        opts.optopt("", "error-format", "rustc error format", "FORMAT");
-        opts.optflag("", "json-output", "use message-format=json");
-        opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
-        opts.optopt(
-            "",
-            "rust-profile-generate",
-            "generate PGO profile with rustc build",
-            "PROFILE",
-        );
-        opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "PROFILE");
-        opts.optflag("", "llvm-profile-generate", "generate PGO profile with llvm built for rustc");
-        opts.optopt("", "llvm-profile-use", "use PGO profile for llvm build", "PROFILE");
-        opts.optmulti("A", "", "allow certain clippy lints", "OPT");
-        opts.optmulti("D", "", "deny certain clippy lints", "OPT");
-        opts.optmulti("W", "", "warn about certain clippy lints", "OPT");
-        opts.optmulti("F", "", "forbid certain clippy lints", "OPT");
-        opts.optflag("", "llvm-bolt-profile-generate", "generate BOLT profile for LLVM build");
-        opts.optopt("", "llvm-bolt-profile-use", "use BOLT profile for LLVM build", "PROFILE");
-
-        // We can't use getopt to parse the options until we have completed specifying which
-        // options are valid, but under the current implementation, some options are conditional on
-        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
-        // complete the definition of the options.  Then we can use the getopt::Matches object from
-        // there on out.
-        let subcommand = match args.iter().find_map(|s| Kind::parse(&s)) {
-            Some(s) => s,
-            None => {
-                // No or an invalid subcommand -- show the general usage and subcommand help
-                // An exit code will be 0 when no subcommand is given, and 1 in case of an invalid
-                // subcommand.
-                println!("{}\n", subcommand_help);
-                let exit_code = if args.is_empty() { 0 } else { 1 };
-                crate::detail_exit(exit_code);
-            }
-        };
-
-        // Some subcommands get extra options
-        match subcommand {
-            Kind::Test => {
-                opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
-                opts.optmulti("", "skip", "skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times", "SUBSTRING");
-                opts.optmulti(
-                    "",
-                    "test-args",
-                    "extra arguments to be passed for the test tool being used \
-                        (e.g. libtest, compiletest or rustdoc)",
-                    "ARGS",
-                );
-                opts.optmulti(
-                    "",
-                    "rustc-args",
-                    "extra options to pass the compiler when running tests",
-                    "ARGS",
-                );
-                opts.optflag("", "no-doc", "do not run doc tests");
-                opts.optflag("", "doc", "only run doc tests");
-                opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
-                opts.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged");
-                opts.optflag("", "only-modified", "only run tests that result has been changed");
-                opts.optopt(
-                    "",
-                    "compare-mode",
-                    "mode describing what file the actual ui output will be compared to",
-                    "COMPARE MODE",
-                );
-                opts.optopt(
-                    "",
-                    "pass",
-                    "force {check,build,run}-pass tests to this mode.",
-                    "check | build | run",
-                );
-                opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
-                opts.optflag(
-                    "",
-                    "rustfix-coverage",
-                    "enable this to generate a Rustfix coverage file, which is saved in \
-                        `/<build_base>/rustfix_missing_coverage.txt`",
-                );
-            }
-            Kind::Check => {
-                opts.optflag("", "all-targets", "Check all targets");
-            }
-            Kind::Bench => {
-                opts.optmulti("", "test-args", "extra arguments", "ARGS");
-            }
-            Kind::Clippy => {
-                opts.optflag("", "fix", "automatically apply lint suggestions");
-            }
-            Kind::Doc => {
-                opts.optflag("", "open", "open the docs in a browser");
-                opts.optflag(
-                    "",
-                    "json",
-                    "render the documentation in JSON format in addition to the usual HTML format",
-                );
-            }
-            Kind::Clean => {
-                opts.optflag("", "all", "clean all build artifacts");
-            }
-            Kind::Format => {
-                opts.optflag("", "check", "check formatting instead of applying.");
-            }
-            Kind::Run => {
-                opts.optmulti("", "args", "arguments for the tool", "ARGS");
-            }
-            Kind::Suggest => {
-                opts.optflag("", "run", "run suggested tests");
-            }
-            _ => {}
-        };
-
-        // fn usage()
-        let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
-            println!("{}", opts.usage(subcommand_help));
-            if verbose {
-                // We have an unfortunate situation here: some Steps use `builder.in_tree_crates` to determine their paths.
-                // To determine those crates, we need to run `cargo metadata`, which means we need all submodules to be checked out.
-                // That takes a while to run, so only do it when paths were explicitly requested, not on all CLI errors.
-                // `Build::new` won't load submodules for the `setup` command.
-                let cmd = if verbose {
-                    println!("note: updating submodules before printing available paths");
-                    "build"
-                } else {
-                    "setup"
-                };
-                let config = Config::parse(&[cmd.to_string()]);
-                let build = Build::new(config);
-                let paths = Builder::get_help(&build, subcommand);
-
-                if let Some(s) = paths {
-                    println!("{}", s);
-                } else {
-                    panic!("No paths available for subcommand `{}`", subcommand.as_str());
-                }
+    pub fn parse(args: &[String]) -> Self {
+        let first = String::from("x.py");
+        let it = std::iter::once(&first).chain(args.iter());
+        // We need to check for `<cmd> -h -v`, in which case we list the paths
+        #[derive(Parser)]
+        #[clap(disable_help_flag(true))]
+        struct HelpVerboseOnly {
+            #[arg(short, long)]
+            help: bool,
+            #[arg(global(true), short, long, action = clap::ArgAction::Count)]
+            pub verbose: u8,
+            #[arg(value_enum)]
+            cmd: Kind,
+        }
+        if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
+            HelpVerboseOnly::try_parse_from(it.clone())
+        {
+            println!("note: updating submodules before printing available paths");
+            let config = Config::parse(&[String::from("build")]);
+            let build = Build::new(config);
+            let paths = Builder::get_help(&build, subcommand);
+            if let Some(s) = paths {
+                println!("{}", s);
             } else {
-                println!(
-                    "Run `./x.py {} -h -v` to see a list of available paths.",
-                    subcommand.as_str()
-                );
-            }
-            crate::detail_exit(exit_code);
-        };
-
-        // Done specifying what options are possible, so do the getopts parsing
-        let matches = opts.parse(args).unwrap_or_else(|e| {
-            // Invalid argument/option format
-            println!("\n{}\n", e);
-            usage(1, &opts, false, &subcommand_help);
-        });
-
-        // Extra sanity check to make sure we didn't hit this crazy corner case:
-        //
-        //     ./x.py --frobulate clean build
-        //            ^-- option  ^     ^- actual subcommand
-        //                        \_ arg to option could be mistaken as subcommand
-        let mut pass_sanity_check = true;
-        match matches.free.get(0).and_then(|s| Kind::parse(&s)) {
-            Some(check_subcommand) => {
-                if check_subcommand != subcommand {
-                    pass_sanity_check = false;
-                }
-            }
-            None => {
-                pass_sanity_check = false;
+                panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
+            crate::detail_exit(0);
         }
-        if !pass_sanity_check {
-            eprintln!("{}\n", subcommand_help);
-            eprintln!(
-                "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
-                 You may need to move some options to after the subcommand.\n"
-            );
-            crate::detail_exit(1);
-        }
-        // Extra help text for some commands
-        match subcommand {
-            Kind::Build => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to compile. For example, for a quick build of a usable
-    compiler:
 
-        ./x.py build --stage 1 library/std
+        Flags::parse_from(it)
+    }
+}
 
-    This will build a compiler and standard library from the local source code.
-    Once this is done, build/$ARCH/stage1 contains a usable compiler.
-
-    If no arguments are passed then the default artifacts for that stage are
-    compiled. For example:
-
-        ./x.py build --stage 0
-        ./x.py build ",
-                );
-            }
-            Kind::Check => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to compile. For example:
-
-        ./x.py check library/std
-
-    If no arguments are passed then many artifacts are checked.",
-                );
-            }
-            Kind::Clippy => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to run clippy against. For example:
-
-        ./x.py clippy library/core
-        ./x.py clippy library/core library/proc_macro",
-                );
-            }
-            Kind::Fix => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to run `cargo fix` against. For example:
-
-        ./x.py fix library/core
-        ./x.py fix library/core library/proc_macro",
-                );
-            }
-            Kind::Format => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and
-    fails if it is not. For example:
-
-        ./x.py fmt
-        ./x.py fmt --check",
-                );
-            }
-            Kind::Test => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to test directories that
-    should be compiled and run. For example:
-
-        ./x.py test tests/ui
-        ./x.py test library/std --test-args hash_map
-        ./x.py test library/std --stage 0 --no-doc
-        ./x.py test tests/ui --bless
-        ./x.py test tests/ui --compare-mode chalk
-
-    Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
-    just like `build library/std --stage N` it tests the compiler produced by the previous
-    stage.
-
-    Execute tool tests with a tool name argument:
-
-        ./x.py test tidy
-
-    If no arguments are passed then the complete artifacts for that stage are
-    compiled and tested.
-
-        ./x.py test
-        ./x.py test --stage 1",
-                );
-            }
-            Kind::Doc => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to directories of documentation
-    to build. For example:
-
-        ./x.py doc src/doc/book
-        ./x.py doc src/doc/nomicon
-        ./x.py doc src/doc/book library/std
-        ./x.py doc library/std --json
-        ./x.py doc library/std --open
-
-    If no arguments are passed then everything is documented:
-
-        ./x.py doc
-        ./x.py doc --stage 1",
-                );
-            }
-            Kind::Run => {
-                subcommand_help.push_str(
-                    "\n
-Arguments:
-    This subcommand accepts a number of paths to tools to build and run. For
-    example:
-
-        ./x.py run src/tools/expand-yaml-anchors
-
-    At least a tool needs to be called.",
-                );
-            }
-            Kind::Setup => {
-                subcommand_help.push_str(&format!(
-                    "\n
+#[derive(Debug, Clone, Default, clap::Subcommand)]
+pub enum Subcommand {
+    #[clap(aliases = ["b"], long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to directories to the crates
+        and/or artifacts to compile. For example, for a quick build of a usable
+        compiler:
+            ./x.py build --stage 1 library/std
+        This will build a compiler and standard library from the local source code.
+        Once this is done, build/$ARCH/stage1 contains a usable compiler.
+        If no arguments are passed then the default artifacts for that stage are
+        compiled. For example:
+            ./x.py build --stage 0
+            ./x.py build ")]
+    /// Compile either the compiler or libraries
+    #[default]
+    Build,
+    #[clap(aliases = ["c"], long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to directories to the crates
+        and/or artifacts to compile. For example:
+            ./x.py check library/std
+        If no arguments are passed then many artifacts are checked.")]
+    /// Compile either the compiler or libraries, using cargo check
+    Check {
+        #[arg(long)]
+        /// Check all targets
+        all_targets: bool,
+    },
+    /// Run Clippy (uses rustup/cargo-installed clippy binary)
+    #[clap(long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to directories to the crates
+        and/or artifacts to run clippy against. For example:
+            ./x.py clippy library/core
+            ./x.py clippy library/core library/proc_macro")]
+    Clippy {
+        #[arg(long)]
+        fix: bool,
+        /// clippy lints to allow
+        #[arg(global(true), short = 'A', action = clap::ArgAction::Append, value_name = "LINT")]
+        allow: Vec<String>,
+        /// clippy lints to deny
+        #[arg(global(true), short = 'D', action = clap::ArgAction::Append, value_name = "LINT")]
+        deny: Vec<String>,
+        /// clippy lints to warn on
+        #[arg(global(true), short = 'W', action = clap::ArgAction::Append, value_name = "LINT")]
+        warn: Vec<String>,
+        /// clippy lints to forbid
+        #[arg(global(true), short = 'F', action = clap::ArgAction::Append, value_name = "LINT")]
+        forbid: Vec<String>,
+    },
+    /// Run cargo fix
+    #[clap(long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to directories to the crates
+        and/or artifacts to run `cargo fix` against. For example:
+            ./x.py fix library/core
+            ./x.py fix library/core library/proc_macro")]
+    Fix,
+    #[clap(
+        name = "fmt",
+        long_about = "\n
+    Arguments:
+        This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and
+        fails if it is not. For example:
+            ./x.py fmt
+            ./x.py fmt --check"
+    )]
+    /// Run rustfmt
+    Format {
+        /// check formatting instead of applying
+        #[arg(long)]
+        check: bool,
+    },
+    #[clap(aliases = ["d"], long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to directories of documentation
+        to build. For example:
+            ./x.py doc src/doc/book
+            ./x.py doc src/doc/nomicon
+            ./x.py doc src/doc/book library/std
+            ./x.py doc library/std --json
+            ./x.py doc library/std --open
+        If no arguments are passed then everything is documented:
+            ./x.py doc
+            ./x.py doc --stage 1")]
+    /// Build documentation
+    Doc {
+        #[arg(long)]
+        /// open the docs in a browser
+        open: bool,
+        #[arg(long)]
+        /// render the documentation in JSON format in addition to the usual HTML format
+        json: bool,
+    },
+    #[clap(aliases = ["t"], long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to test directories that
+        should be compiled and run. For example:
+            ./x.py test tests/ui
+            ./x.py test library/std --test-args hash_map
+            ./x.py test library/std --stage 0 --no-doc
+            ./x.py test tests/ui --bless
+            ./x.py test tests/ui --compare-mode chalk
+        Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
+        just like `build library/std --stage N` it tests the compiler produced by the previous
+        stage.
+        Execute tool tests with a tool name argument:
+            ./x.py test tidy
+        If no arguments are passed then the complete artifacts for that stage are
+        compiled and tested.
+            ./x.py test
+            ./x.py test --stage 1")]
+    /// Build and run some test suites
+    Test {
+        #[arg(long)]
+        /// run all tests regardless of failure
+        no_fail_fast: bool,
+        #[arg(long, value_name = "SUBSTRING")]
+        /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times
+        skip: Vec<String>,
+        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
+        /// extra arguments to be passed for the test tool being used
+        /// (e.g. libtest, compiletest or rustdoc)
+        test_args: Vec<String>,
+        /// extra options to pass the compiler when running tests
+        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
+        rustc_args: Vec<String>,
+        #[arg(long)]
+        /// do not run doc tests
+        no_doc: bool,
+        #[arg(long)]
+        /// only run doc tests
+        doc: bool,
+        #[arg(long)]
+        /// whether to automatically update stderr/stdout files
+        bless: bool,
+        #[arg(long)]
+        /// rerun tests even if the inputs are unchanged
+        force_rerun: bool,
+        #[arg(long)]
+        /// only run tests that result has been changed
+        only_modified: bool,
+        #[arg(long, value_name = "COMPARE MODE")]
+        /// mode describing what file the actual ui output will be compared to
+        compare_mode: Option<String>,
+        #[arg(long, value_name = "check | build | run")]
+        /// force {check,build,run}-pass tests to this mode.
+        pass: Option<String>,
+        #[arg(long, value_name = "auto | always | never")]
+        /// whether to execute run-* tests
+        run: Option<String>,
+        #[arg(long)]
+        /// enable this to generate a Rustfix coverage file, which is saved in
+        /// `/<build_base>/rustfix_missing_coverage.txt`
+        rustfix_coverage: bool,
+    },
+    /// Build and run some benchmarks
+    Bench {
+        #[arg(long, allow_hyphen_values(true))]
+        test_args: Vec<String>,
+    },
+    /// Clean out build directories
+    Clean {
+        #[arg(long)]
+        all: bool,
+    },
+    /// Duild distribution artifacts
+    Dist,
+    /// Install distribution artifacts
+    Install,
+    #[clap(aliases = ["r"], long_about = "\n
+    Arguments:
+        This subcommand accepts a number of paths to tools to build and run. For
+        example:
+            ./x.py run src/tools/expand-yaml-anchors
+        At least a tool needs to be called.")]
+    /// Run tools contained in this repository
+    Run {
+        /// arguments for the tool
+        #[arg(long, allow_hyphen_values(true))]
+        args: Vec<String>,
+    },
+    /// Set up the environment for development
+    #[clap(long_about = format!(
+        "\n
 x.py setup creates a `config.toml` which changes the defaults for x.py itself,
-as well as setting up a git pre-push hook, VS code config and toolchain link.
-
+as well as setting up a git pre-push hook, VS Code config and toolchain link.
 Arguments:
     This subcommand accepts a 'profile' to use for builds. For example:
-
         ./x.py setup library
-
     The profile is optional and you will be prompted interactively if it is not given.
     The following profiles are available:
-
 {}
-
-    To only set up the git hook, VS code or toolchain link, you may use
+    To only set up the git hook, VS Code config or toolchain link, you may use
         ./x.py setup hook
         ./x.py setup vscode
-        ./x.py setup link
-",
-                    Profile::all_for_help("        ").trim_end()
-                ));
-            }
-            Kind::Bench | Kind::Clean | Kind::Dist | Kind::Install | Kind::Suggest => {}
-        };
-        // Get any optional paths which occur after the subcommand
-        let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
-
-        let verbose = matches.opt_present("verbose");
-
-        // User passed in -h/--help?
-        if matches.opt_present("help") {
-            usage(0, &opts, verbose, &subcommand_help);
-        }
-
-        let cmd = match subcommand {
-            Kind::Build => Subcommand::Build { paths },
-            Kind::Check => {
-                if matches.opt_present("all-targets") {
-                    println!(
-                        "Warning: --all-targets is now on by default and does not need to be passed explicitly."
-                    );
-                }
-                Subcommand::Check { paths }
-            }
-            Kind::Clippy => Subcommand::Clippy {
-                paths,
-                fix: matches.opt_present("fix"),
-                clippy_lint_allow: matches.opt_strs("A"),
-                clippy_lint_warn: matches.opt_strs("W"),
-                clippy_lint_deny: matches.opt_strs("D"),
-                clippy_lint_forbid: matches.opt_strs("F"),
-            },
-            Kind::Fix => Subcommand::Fix { paths },
-            Kind::Test => Subcommand::Test {
-                paths,
-                bless: matches.opt_present("bless"),
-                force_rerun: matches.opt_present("force-rerun"),
-                compare_mode: matches.opt_str("compare-mode"),
-                pass: matches.opt_str("pass"),
-                run: matches.opt_str("run"),
-                test_args: matches.opt_strs("test-args"),
-                rustc_args: matches.opt_strs("rustc-args"),
-                fail_fast: !matches.opt_present("no-fail-fast"),
-                rustfix_coverage: matches.opt_present("rustfix-coverage"),
-                only_modified: matches.opt_present("only-modified"),
-                doc_tests: if matches.opt_present("doc") {
-                    DocTests::Only
-                } else if matches.opt_present("no-doc") {
-                    DocTests::No
-                } else {
-                    DocTests::Yes
-                },
-            },
-            Kind::Bench => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
-            Kind::Doc => Subcommand::Doc {
-                paths,
-                open: matches.opt_present("open"),
-                json: matches.opt_present("json"),
-            },
-            Kind::Clean => Subcommand::Clean { all: matches.opt_present("all"), paths },
-            Kind::Format => Subcommand::Format { check: matches.opt_present("check"), paths },
-            Kind::Dist => Subcommand::Dist { paths },
-            Kind::Install => Subcommand::Install { paths },
-            Kind::Suggest => Subcommand::Suggest { run: matches.opt_present("run") },
-            Kind::Run => {
-                if paths.is_empty() {
-                    println!("\nrun requires at least a path!\n");
-                    usage(1, &opts, verbose, &subcommand_help);
-                }
-                Subcommand::Run { paths, args: matches.opt_strs("args") }
-            }
-            Kind::Setup => {
-                let profile = if paths.len() > 1 {
-                    eprintln!("\nerror: At most one option can be passed to setup\n");
-                    usage(1, &opts, verbose, &subcommand_help)
-                } else if let Some(path) = paths.pop() {
-                    let profile_string = t!(path.into_os_string().into_string().map_err(
-                        |path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
-                    ));
-
-                    let profile = profile_string.parse().unwrap_or_else(|err| {
-                        eprintln!("error: {}", err);
-                        eprintln!("help: the available profiles are:");
-                        eprint!("{}", Profile::all_for_help("- "));
-                        crate::detail_exit(1);
-                    });
-                    Some(profile)
-                } else {
-                    None
-                };
-                Subcommand::Setup { profile }
-            }
-        };
-
-        Flags {
-            verbose: matches.opt_count("verbose"),
-            stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
-            dry_run: matches.opt_present("dry-run"),
-            on_fail: matches.opt_str("on-fail"),
-            rustc_error_format: matches.opt_str("error-format"),
-            json_output: matches.opt_present("json-output"),
-            keep_stage: matches
-                .opt_strs("keep-stage")
-                .into_iter()
-                .map(|j| j.parse().expect("`keep-stage` should be a number"))
-                .collect(),
-            keep_stage_std: matches
-                .opt_strs("keep-stage-std")
-                .into_iter()
-                .map(|j| j.parse().expect("`keep-stage-std` should be a number"))
-                .collect(),
-            host: if matches.opt_present("host") {
-                Some(
-                    split(&matches.opt_strs("host"))
-                        .into_iter()
-                        .map(|x| TargetSelection::from_user(&x))
-                        .collect::<Vec<_>>(),
-                )
-            } else {
-                None
-            },
-            target: if matches.opt_present("target") {
-                Some(
-                    split(&matches.opt_strs("target"))
-                        .into_iter()
-                        .map(|x| TargetSelection::from_user(&x))
-                        .collect::<Vec<_>>(),
-                )
-            } else {
-                None
-            },
-            config: matches.opt_str("config").map(PathBuf::from),
-            build_dir: matches.opt_str("build-dir").map(PathBuf::from),
-            jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
-            cmd,
-            incremental: matches.opt_present("incremental"),
-            exclude: split(&matches.opt_strs("exclude"))
-                .into_iter()
-                .map(|p| p.into())
-                .collect::<Vec<_>>(),
-            include_default_paths: matches.opt_present("include-default-paths"),
-            deny_warnings: parse_deny_warnings(&matches),
-            color: matches
-                .opt_get_default("color", Color::Auto)
-                .expect("`color` should be `always`, `never`, or `auto`"),
-            rust_profile_use: matches.opt_str("rust-profile-use"),
-            rust_profile_generate: matches.opt_str("rust-profile-generate"),
-            llvm_profile_use: matches.opt_str("llvm-profile-use"),
-            llvm_profile_generate: matches.opt_present("llvm-profile-generate"),
-            llvm_bolt_profile_generate: matches.opt_present("llvm-bolt-profile-generate"),
-            llvm_bolt_profile_use: matches.opt_str("llvm-bolt-profile-use"),
-            free_args,
-        }
-    }
+        ./x.py setup link", Profile::all_for_help("        ").trim_end()))]
+    Setup {
+        /// Either the profile for `config.toml` or another setup action.
+        /// May be omitted to set up interactively
+        #[arg(value_name = "<PROFILE>|hook|vscode|link")]
+        profile: Option<PathBuf>,
+    },
+    /// Suggest a subset of tests to run, based on modified files
+    #[clap(long_about = "\n")]
+    Suggest {
+        /// run suggested tests
+        #[arg(long)]
+        run: bool,
+    },
 }
 
 impl Subcommand {
@@ -756,14 +441,22 @@ impl Subcommand {
 
     pub fn fail_fast(&self) -> bool {
         match *self {
-            Subcommand::Test { fail_fast, .. } => fail_fast,
+            Subcommand::Test { no_fail_fast, .. } => !no_fail_fast,
             _ => false,
         }
     }
 
     pub fn doc_tests(&self) -> DocTests {
         match *self {
-            Subcommand::Test { doc_tests, .. } => doc_tests,
+            Subcommand::Test { doc, no_doc, .. } => {
+                if doc {
+                    DocTests::Only
+                } else if no_doc {
+                    DocTests::No
+                } else {
+                    DocTests::Yes
+                }
+            }
             _ => DocTests::Yes,
         }
     }
@@ -831,19 +524,3 @@ impl Subcommand {
         }
     }
 }
-
-fn split(s: &[String]) -> Vec<String> {
-    s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect()
-}
-
-fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
-    match matches.opt_str("warnings").as_deref() {
-        Some("deny") => Some(true),
-        Some("warn") => Some(false),
-        Some(value) => {
-            eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,);
-            crate::detail_exit(1);
-        }
-        None => None,
-    }
-}
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 59d2e9cc69e..994336977dc 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -660,8 +660,8 @@ impl Build {
 
         // hardcoded subcommands
         match &self.config.cmd {
-            Subcommand::Format { check, paths } => {
-                return format::format(&builder::Builder::new(&self), *check, &paths);
+            Subcommand::Format { check } => {
+                return format::format(&builder::Builder::new(&self), *check, &self.config.paths);
             }
             Subcommand::Suggest { run } => {
                 return suggest::suggest(&builder::Builder::new(&self), *run);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 28813266a4d..854b7f5bd3a 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1545,7 +1545,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the
 
         // Get paths from cmd args
         let paths = match &builder.config.cmd {
-            Subcommand::Test { ref paths, .. } => &paths[..],
+            Subcommand::Test { .. } => &builder.config.paths[..],
             _ => &[],
         };
 
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
index 9a1b3e3641a..3ac5343aa57 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
@@ -8,7 +8,6 @@ RUN sh /scripts/crosstool-ng.sh
 
 WORKDIR /build
 
-COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
index 13eaf7fce8c..6f04dcad9a5 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
@@ -25,7 +25,6 @@ WORKDIR /build/
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
 # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
 RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \
diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile
index 62e3f627ec0..1dc7b798724 100644
--- a/src/ci/docker/host-x86_64/test-various/Dockerfile
+++ b/src/ci/docker/host-x86_64/test-various/Dockerfile
@@ -33,7 +33,6 @@ RUN curl -sL --output ovmf-ia32.deb http://mirrors.kernel.org/ubuntu/pool/univer
 RUN dpkg -i ovmf-ia32.deb && rm ovmf-ia32.deb
 
 WORKDIR /build/
-COPY scripts/musl-patch-configure.diff /build/
 COPY scripts/musl-toolchain.sh /build/
 RUN bash musl-toolchain.sh x86_64 && rm -rf build
 WORKDIR /
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 69d4916e5a9..8bea8cd4c87 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -169,6 +169,7 @@ if [ "$SCCACHE_BUCKET" != "" ]; then
     args="$args --env SCCACHE_REGION"
     args="$args --env AWS_ACCESS_KEY_ID"
     args="$args --env AWS_SECRET_ACCESS_KEY"
+    args="$args --env AWS_REGION"
 else
     mkdir -p $HOME/.cache/sccache
     args="$args --env SCCACHE_DIR=/sccache --volume $HOME/.cache/sccache:/sccache"
diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh
index e358b8139d7..bc1b30e2d31 100644
--- a/src/ci/docker/scripts/musl-toolchain.sh
+++ b/src/ci/docker/scripts/musl-toolchain.sh
@@ -4,7 +4,7 @@
 #
 # Versions of the toolchain components are configurable in `musl-cross-make/Makefile` and
 # musl unlike GLIBC is forward compatible so upgrading it shouldn't break old distributions.
-# Right now we have: Binutils 2.31.1, GCC 9.2.0, musl 1.1.24.
+# Right now we have: Binutils 2.31.1, GCC 9.2.0, musl 1.2.3.
 
 # ignore-tidy-linelength
 
@@ -32,6 +32,7 @@ TARGET=$ARCH-linux-musl
 
 # Don't depend on the mirrors of sabotage linux that musl-cross-make uses.
 LINUX_HEADERS_SITE=https://ci-mirrors.rust-lang.org/rustc/sabotage-linux-tarballs
+LINUX_VER=headers-4.19.88
 
 OUTPUT=/usr/local
 shift
@@ -44,18 +45,11 @@ export CFLAGS="-fPIC -g1 $CFLAGS"
 
 git clone https://github.com/richfelker/musl-cross-make # -b v0.9.9
 cd musl-cross-make
-# A few commits ahead of v0.9.9 to include the cowpatch fix:
-git checkout a54eb56f33f255dfca60be045f12a5cfaf5a72a9
+# A version that includes support for building musl 1.2.3
+git checkout fe915821b652a7fa37b34a596f47d8e20bc72338
 
-# Fix the cfi detection script in musl's configure so cfi is generated
-# when debug info is asked for. This patch is derived from
-# https://git.musl-libc.org/cgit/musl/commit/?id=c4d4028dde90562f631edf559fbc42d8ec1b29de.
-# When we upgrade to a version that includes this commit, we can remove the patch.
-mkdir patches/musl-1.1.24
-cp ../musl-patch-configure.diff patches/musl-1.1.24/0001-fix-cfi-detection.diff
-
-hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.1.24 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE
-hide_output make install TARGET=$TARGET MUSL_VER=1.1.24 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE OUTPUT=$OUTPUT
+hide_output make -j$(nproc) TARGET=$TARGET MUSL_VER=1.2.3 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER
+hide_output make install TARGET=$TARGET MUSL_VER=1.2.3 LINUX_HEADERS_SITE=$LINUX_HEADERS_SITE LINUX_VER=$LINUX_VER OUTPUT=$OUTPUT
 
 cd -
 
diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh
index 3e5dc4af04a..ece8e6c15c0 100644
--- a/src/ci/docker/scripts/musl.sh
+++ b/src/ci/docker/scripts/musl.sh
@@ -25,7 +25,7 @@ shift
 # Apparently applying `-fPIC` everywhere allows them to link successfully.
 export CFLAGS="-fPIC $CFLAGS"
 
-MUSL=musl-1.1.24
+MUSL=musl-1.2.3
 
 # may have been downloaded in a previous run
 if [ ! -d $MUSL ]; then
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 5661adf6776..f81e740936b 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -53,6 +53,7 @@ x--expand-yaml-anchors--remove:
     # (caches, artifacts...).
     CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
     ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+    AWS_REGION: us-west-1
     CACHE_DOMAIN: ci-caches.rust-lang.org
 
   - &dummy-variables
@@ -68,6 +69,7 @@ x--expand-yaml-anchors--remove:
     # (caches, artifacts...).
     CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
     ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
+    AWS_REGION: us-west-1
     CACHE_DOMAIN: ci-caches-gha.rust-lang.org
 
   - &base-job
@@ -158,10 +160,6 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/dump-environment.sh
         <<: *step
 
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        <<: *step
-
       - name: install sccache
         run: src/ci/scripts/install-sccache.sh
         <<: *step
@@ -300,25 +298,21 @@ jobs:
     env:
       <<: [*shared-ci-variables, *public-variables]
     if: github.event_name == 'pull_request'
-    continue-on-error: ${{ matrix.tidy }}
+    continue-on-error: ${{ matrix.name == 'mingw-check-tidy' }}
     strategy:
       matrix:
         include:
           - name: mingw-check
             <<: *job-linux-16c
-            tidy: false
 
           - name: mingw-check-tidy
             <<: *job-linux-16c
-            tidy: true
 
           - name: x86_64-gnu-llvm-14
             <<: *job-linux-16c
-            tidy: false
 
           - name: x86_64-gnu-tools
             <<: *job-linux-16c
-            tidy: false
 
   auto:
     permissions:
diff --git a/src/ci/scripts/install-awscli.sh b/src/ci/scripts/install-awscli.sh
deleted file mode 100755
index aa62407eaea..00000000000
--- a/src/ci/scripts/install-awscli.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/bin/bash
-# This script downloads and installs awscli from the packages mirrored in our
-# own S3 bucket. This follows the recommendations at:
-#
-#    https://packaging.python.org/guides/index-mirrors-and-caches/#caching-with-pip
-#
-# To create a new mirrored copy you can run the command:
-#
-#    pip wheel awscli
-#
-# Before compressing please make sure all the wheels end with `-none-any.whl`.
-# If that's not the case you'll need to remove the non-cross-platform ones and
-# replace them with the .tar.gz downloaded from https://pypi.org.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
-
-MIRROR="${MIRRORS_BASE}/2023-04-28-awscli.tar"
-DEPS_DIR="/tmp/awscli-deps"
-
-pip="pip"
-pipflags=""
-if isLinux; then
-    pip="pip3"
-    pipflags="--user"
-
-    sudo apt-get install -y python3-setuptools python3-wheel
-    ciCommandAddPath "${HOME}/.local/bin"
-elif isMacOS; then
-    pip="pip3"
-fi
-
-mkdir -p "${DEPS_DIR}"
-curl "${MIRROR}" | tar xf - -C "${DEPS_DIR}"
-"${pip}" install ${pipflags} --no-index "--find-links=${DEPS_DIR}" awscli
-rm -rf "${DEPS_DIR}"
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index d7c6a884fc8..1041d502669 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -90,6 +90,14 @@ It takes one of the following values:
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.
 
+## dlltool
+
+On `windows-gnu` targets, this flag controls which dlltool `rustc` invokes to
+generate import libraries when using the [`raw-dylib` link kind](../../reference/items/external-blocks.md#the-link-attribute).
+It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs/binutils/dlltool.html).
+If this flag is not specified, a dlltool executable will be inferred based on
+the host environment and target.
+
 ## embed-bitcode
 
 This flag controls whether or not the compiler embeds LLVM bitcode into object
@@ -574,7 +582,8 @@ change in the future.
 This instructs `rustc` to generate code specifically for a particular processor.
 
 You can run `rustc --print target-cpus` to see the valid options to pass
-here. Each target has a default base CPU. Special values include:
+and the default target CPU for the current buid target.
+Each target has a default base CPU. Special values include:
 
 * `native` can be passed to use the processor of the host machine.
 * `generic` refers to an LLVM target with minimal features but modern tuning.
diff --git a/src/doc/unstable-book/src/compiler-flags/extern-options.md b/src/doc/unstable-book/src/compiler-flags/extern-options.md
index dfc1de77be4..087b37dd8de 100644
--- a/src/doc/unstable-book/src/compiler-flags/extern-options.md
+++ b/src/doc/unstable-book/src/compiler-flags/extern-options.md
@@ -4,6 +4,7 @@
 * Tracking issue for `noprelude`: [#98398](https://github.com/rust-lang/rust/issues/98398)
 * Tracking issue for `priv`: [#98399](https://github.com/rust-lang/rust/issues/98399)
 * Tracking issue for `nounused`: [#98400](https://github.com/rust-lang/rust/issues/98400)
+* Tracking issue for `force`: [#111302](https://github.com/rust-lang/rust/issues/111302)
 
 The behavior of the `--extern` flag can be modified with `noprelude`, `priv` or `nounused` options.
 
@@ -25,3 +26,4 @@ To use multiple options, separate them with a comma:
   This is used by the [build-std project](https://github.com/rust-lang/wg-cargo-std-aware/) to simulate compatibility with sysroot-only crates.
 * `priv`: Mark the crate as a private dependency for the [`exported_private_dependencies`](../../rustc/lints/listing/warn-by-default.html#exported-private-dependencies) lint.
 * `nounused`: Suppress [`unused-crate-dependencies`](../../rustc/lints/listing/allowed-by-default.html#unused-crate-dependencies) warnings for the crate.
+* `force`: Resolve the crate as if it is used, even if it is not used. This can be used to satisfy compilation session requirements like the presence of an allocator or panic handler.
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index 1874baa0c38..532cb9eea11 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -18,6 +18,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - MSP430
 - M68k
 - LoongArch
+- s390x
 
 ## Register classes
 
@@ -48,6 +49,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `reg_addr`     | `a[0-3]`                           | `a`                  |
 | LoongArch    | `reg`          | `$r1`, `$r[4-20]`, `$r[23,30]`     | `r`                  |
 | LoongArch    | `freg`         | `$f[0-31]`                         | `f`                  |
+| s390x        | `reg`          | `r[0-10]`, `r[12-14]`              | `r`                  |
+| s390x        | `freg`         | `f[0-15]`                          | `f`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -81,6 +84,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | M68k         | `reg_data`                      | None           | `i8`, `i16`, `i32`                      |
 | LoongArch64  | `reg`                           | None           | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
 | LoongArch64  | `freg`                          | None           | `f32`, `f64`                            |
+| s390x        | `reg`                           | None           | `i8`, `i16`, `i32`, `i64`               |
+| s390x        | `freg`                          | None           | `f32`, `f64`                            |
 
 ## Register aliases
 
@@ -115,8 +120,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| All          | `sp`                                    | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output.                                                                                                                             |
+| All          | `sp`, `r15` (s390x)                     | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
+| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output.                                                                                                                             |
 | All          | `r19` (Hexagon)                         | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
@@ -147,6 +152,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | PowerPC      | `freg`         | None     | `0`            | None          |
 | LoongArch    | `reg`          | None     | `$r2`          | None          |
 | LoongArch    | `freg`         | None     | `$f0`          | None          |
+| s390x        | `reg`          | None     | `%r0`          | None          |
+| s390x        | `freg`         | None     | `%f0`          | None          |
 
 # Flags covered by `preserves_flags`
 
@@ -157,3 +164,5 @@ These flags registers must be restored upon exiting the asm block if the `preser
   - The status register `r2`.
 - M68k
   - The condition code register `ccr`.
+- s390x
+  - The condition code register `cc`.
diff --git a/src/doc/unstable-book/src/language-features/raw-dylib.md b/src/doc/unstable-book/src/language-features/raw-dylib.md
deleted file mode 100644
index 5fd208ae757..00000000000
--- a/src/doc/unstable-book/src/language-features/raw-dylib.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# `raw_dylib`
-
-The tracking issue for this feature is: [#58713]
-
-[#58713]: https://github.com/rust-lang/rust/issues/58713
-
-------------------------
-
-The `raw_dylib` feature allows you to link against the implementations of functions in an `extern`
-block without, on Windows, linking against an import library.
-
-```rust,ignore (partial-example)
-#![feature(raw_dylib)]
-
-#[link(name="library", kind="raw-dylib")]
-extern {
-    fn extern_function(x: i32);
-}
-
-fn main() {
-    unsafe {
-        extern_function(14);
-    }
-}
-```
-
-## Limitations
-
-This feature is unstable for the `x86` architecture, and stable for all other architectures.
-
-This feature is only supported on Windows.
-
-On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and
-`vectorcall` calling conventions.
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 946c85a205f..c94968b4817 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -811,7 +811,9 @@ impl<'src> Classifier<'src> {
                 | LiteralKind::Str { .. }
                 | LiteralKind::ByteStr { .. }
                 | LiteralKind::RawStr { .. }
-                | LiteralKind::RawByteStr { .. } => Class::String,
+                | LiteralKind::RawByteStr { .. }
+                | LiteralKind::CStr { .. }
+                | LiteralKind::RawCStr { .. } => Class::String,
                 // Number literals.
                 LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
             },
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index f5b4a3f5abd..a3be6dd5269 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -391,12 +391,14 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> {
         clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => {
             get_index_type_id(type_)
         }
+        // The type parameters are converted to generics in `add_generics_and_bounds_as_types`
+        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
+        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
+        // Not supported yet
         clean::BareFunction(_)
         | clean::Generic(_)
         | clean::ImplTrait(_)
         | clean::Tuple(_)
-        | clean::Slice(_)
-        | clean::Array(_, _)
         | clean::QPath { .. }
         | clean::Infer => None,
     }
@@ -563,6 +565,30 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
             }
         }
         insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Slice(ref ty) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
+    } else if let Type::Array(ref ty, _) = *arg {
+        let mut ty_generics = Vec::new();
+        add_generics_and_bounds_as_types(
+            self_,
+            generics,
+            &ty,
+            tcx,
+            recurse + 1,
+            &mut ty_generics,
+            cache,
+        );
+        insert_ty(res, arg.clone(), ty_generics);
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
         // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 263ce3d93b9..b6eb450d62b 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -156,15 +156,19 @@ pub fn main() {
         }
     }
 
-    rustc_driver::install_ice_hook();
+    rustc_driver::install_ice_hook(
+        "https://github.com/rust-lang/rust/issues/new\
+    ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
+        |_| (),
+    );
 
-    // When using CI artifacts (with `download_stage1 = true`), tracing is unconditionally built
+    // When using CI artifacts with `download-rustc`, tracing is unconditionally built
     // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid
     // this, compile our own version of `tracing` that logs all levels.
     // NOTE: this compiles both versions of tracing unconditionally, because
     // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
-    // - Otherwise, there's no warning that logging is being ignored when `download_stage1 = true`.
-    // NOTE: The reason this doesn't show double logging when `download_stage1 = false` and
+    // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
+    // NOTE: The reason this doesn't show double logging when `download-rustc = false` and
     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
     init_logging();
@@ -172,7 +176,11 @@ pub fn main() {
 
     let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
         Some(args) => main_args(&args),
-        _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+        _ =>
+        {
+            #[allow(deprecated)]
+            Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+        }
     });
     process::exit(exit_code);
 }
@@ -725,6 +733,7 @@ fn main_args(at_args: &[String]) -> MainResult {
             return if code == 0 {
                 Ok(())
             } else {
+                #[allow(deprecated)]
                 Err(ErrorGuaranteed::unchecked_claim_error_was_emitted())
             };
         }
diff --git a/src/tools/cargo b/src/tools/cargo
index ac84010322a..569b648b583 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit ac84010322a31f4a581dafe26258aa4ac8dea9cd
+Subproject commit 569b648b5831ae8a515e90c80843a5287c3304ef
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 116058b7c75..0bc2f49f5e9 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -36,6 +36,12 @@ jobs:
     - name: Check *.md files
       run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null
 
+    - name: Linkcheck book
+      run: |
+        rustup toolchain install nightly --component rust-docs
+        curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh
+        sh linkcheck.sh clippy --path ./book
+        
     - name: Build mdbook
       run: mdbook build book
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d7102d2474e..ebf5b58a586 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -44,7 +44,7 @@ Current stable, released 2023-04-20
 
 ### Enhancements
 
-* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used.
+* [`arithmetic_side_effects`]: No longer lints if safe constant values are used.
   [#10310](https://github.com/rust-lang/rust-clippy/pull/10310)
 * [`needless_lifetimes`]: Now works in local macros
   [#10257](https://github.com/rust-lang/rust-clippy/pull/10257)
@@ -60,39 +60,39 @@ Current stable, released 2023-04-20
 
 ### False Positive Fixes
 
-* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable
+* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable
   [#10386](https://github.com/rust-lang/rust-clippy/pull/10386)
-* [`manual_let_else`]: Now considers side effects of branches, before linting 
+* [`manual_let_else`]: Now considers side effects of branches before linting
   [#10336](https://github.com/rust-lang/rust-clippy/pull/10336)
 * [`uninlined_format_args`]: No longer lints for arguments with generic parameters
   [#10343](https://github.com/rust-lang/rust-clippy/pull/10343)
-* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable
+* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable
   [#10380](https://github.com/rust-lang/rust-clippy/pull/10380)
-* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature
+* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature
   [#10255](https://github.com/rust-lang/rust-clippy/pull/10255)
-* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false
+* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false
   positives
   [#10353](https://github.com/rust-lang/rust-clippy/pull/10353)
 * [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent
   [#10332](https://github.com/rust-lang/rust-clippy/pull/10332)
 * [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint
-  in test functions, if `allow-expect-in-tests` is set
+  in test functions if `allow-expect-in-tests` is set
   [#10391](https://github.com/rust-lang/rust-clippy/pull/10391)
 * [`unnecessary_safety_comment`]: No longer lints code inside macros
   [#10106](https://github.com/rust-lang/rust-clippy/pull/10106)
-* [`never_loop`]: No longer lints, for statements following break statements for outer blocks.
+* [`never_loop`]: No longer lints statements following break statements for outer blocks.
   [#10311](https://github.com/rust-lang/rust-clippy/pull/10311)
 
 ### Suggestion Fixes/Improvements
 
-* [`box_default`]: The suggestion now includes the type for trait objects, when needed
+* [`box_default`]: The suggestion now includes the type for trait objects when needed
   [#10382](https://github.com/rust-lang/rust-clippy/pull/10382)
 * [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint
   [#10038](https://github.com/rust-lang/rust-clippy/pull/10038)
 * [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will
   now show the complete error
   [#10231](https://github.com/rust-lang/rust-clippy/pull/10231)
-* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed
+* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed
   [#10193](https://github.com/rust-lang/rust-clippy/pull/10193)
 * [`needless_return`]: Now removes all semicolons on the same line
   [#10187](https://github.com/rust-lang/rust-clippy/pull/10187)
@@ -113,7 +113,7 @@ Current stable, released 2023-04-20
 
 ### ICE Fixes
 
-* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled
+* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled
   [#10328](https://github.com/rust-lang/rust-clippy/pull/10328)
 * [`needless_borrow`]: No longer panics on ambiguous projections
   [#10403](https://github.com/rust-lang/rust-clippy/pull/10403)
@@ -4582,6 +4582,7 @@ Released 2018-09-13
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
+[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs
 [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty
 [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
@@ -4797,6 +4798,7 @@ Released 2018-09-13
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
+[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
@@ -4864,6 +4866,7 @@ Released 2018-09-13
 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 [`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
+[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 4db15ddb283..3c72bb62ed1 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 85798e0e80c..6745e15c006 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -91,7 +91,8 @@ cargo clippy
 
 #### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/src/tools/clippy/book/src/development/lint_passes.md b/src/tools/clippy/book/src/development/lint_passes.md
index 131f6455fde..621fc20972e 100644
--- a/src/tools/clippy/book/src/development/lint_passes.md
+++ b/src/tools/clippy/book/src/development/lint_passes.md
@@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we
 mean when we say `EarlyLintPass` deals with only syntax on the AST level.
 
 Alternatively, think of the `foo_functions` lint we mentioned in
-define new lints chapter.
+define new lints <!-- FIXME: add link --> chapter.
 
 We want the `foo_functions` lint to detect functions with `foo` as their name.
 Writing a lint that only checks for the name of a function means that we only
diff --git a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
index 36d722609f4..285488cec55 100644
--- a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
+++ b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md
@@ -139,7 +139,7 @@ whether the pattern matched.
 
 ## Pattern syntax
 
-The following examples demonstate the pattern syntax:
+The following examples demonstrate the pattern syntax:
 
 
 #### Any (`_`)
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index a702226e861..5646c9b1520 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand.
 | [msrv](#msrv) | `None` |
 | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
 | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` |
+| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` |
 | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
 | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
 | [type-complexity-threshold](#type-complexity-threshold) | `250` |
@@ -203,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the
 * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
 
 
+### semicolon-inside-block-ignore-singleline
+Whether to lint only if it's multiline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block)
+
+
+### semicolon-outside-block-ignore-multiline
+Whether to lint only if it's singleline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block)
+
+
 ### doc-valid-idents
 The list of words this lint should not consider as identifiers needing ticks. The value
 `".."` can be used as part of the list to indicate, that the configured values should be appended to the
diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md
index 32084a9199b..36448e4cccf 100644
--- a/src/tools/clippy/book/src/usage.md
+++ b/src/tools/clippy/book/src/usage.md
@@ -111,7 +111,8 @@ fn main() {
 
 ### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs
index b69e9f649ec..a0d57f5ab48 100644
--- a/src/tools/clippy/clippy_dev/src/dogfood.rs
+++ b/src/tools/clippy/clippy_dev/src/dogfood.rs
@@ -1,4 +1,4 @@
-use crate::clippy_project_root;
+use crate::{clippy_project_root, exit_if_err};
 use std::process::Command;
 
 /// # Panics
@@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
     cmd.current_dir(clippy_project_root())
         .args(["test", "--test", "dogfood"])
         .args(["--features", "internal"])
-        .args(["--", "dogfood_clippy"]);
+        .args(["--", "dogfood_clippy", "--nocapture"]);
 
     let mut dogfood_args = Vec::new();
     if fix {
@@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
 
     cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" "));
 
-    let output = cmd.output().expect("failed to run command");
-
-    println!("{}", String::from_utf8_lossy(&output.stdout));
+    exit_if_err(cmd.status());
 }
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 3a8b070d735..56a269288c0 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -10,7 +10,9 @@
 extern crate rustc_driver;
 extern crate rustc_lexer;
 
+use std::io;
 use std::path::PathBuf;
+use std::process::{self, ExitStatus};
 
 pub mod bless;
 pub mod dogfood;
@@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf {
     }
     panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
 }
+
+pub fn exit_if_err(status: io::Result<ExitStatus>) {
+    match status.expect("failed to run command").code() {
+        Some(0) => {},
+        Some(n) => process::exit(n),
+        None => {
+            eprintln!("Killed by signal");
+            process::exit(1);
+        },
+    }
+}
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index aafd0f71a59..a19be1bca6c 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -1,17 +1,6 @@
-use crate::cargo_clippy_path;
-use std::process::{self, Command, ExitStatus};
-use std::{fs, io};
-
-fn exit_if_err(status: io::Result<ExitStatus>) {
-    match status.expect("failed to run command").code() {
-        Some(0) => {},
-        Some(n) => process::exit(n),
-        None => {
-            eprintln!("Killed by signal");
-            process::exit(1);
-        },
-    }
-}
+use crate::{cargo_clippy_path, exit_if_err};
+use std::fs;
+use std::process::{self, Command};
 
 pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
     let is_file = match fs::metadata(path) {
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index dd90a38f757..7213c9dfede 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -36,60 +36,6 @@ pub enum UpdateMode {
 pub fn update(update_mode: UpdateMode) {
     let (lints, deprecated_lints, renamed_lints) = gather_all();
     generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
-    remove_old_files(update_mode);
-}
-
-/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541>
-/// that may be reintroduced unintentionally
-///
-/// FIXME: This is a temporary measure that should be removed when there are no more PRs that
-/// include the stray files
-fn remove_old_files(update_mode: UpdateMode) {
-    let mut failed = false;
-    let mut remove_file = |path: &Path| match update_mode {
-        UpdateMode::Check => {
-            if path.exists() {
-                failed = true;
-                println!("unexpected file: {}", path.display());
-            }
-        },
-        UpdateMode::Change => {
-            if fs::remove_file(path).is_ok() {
-                println!("removed file: {}", path.display());
-            }
-        },
-    };
-
-    let files = [
-        "clippy_lints/src/lib.register_all.rs",
-        "clippy_lints/src/lib.register_cargo.rs",
-        "clippy_lints/src/lib.register_complexity.rs",
-        "clippy_lints/src/lib.register_correctness.rs",
-        "clippy_lints/src/lib.register_internal.rs",
-        "clippy_lints/src/lib.register_lints.rs",
-        "clippy_lints/src/lib.register_nursery.rs",
-        "clippy_lints/src/lib.register_pedantic.rs",
-        "clippy_lints/src/lib.register_perf.rs",
-        "clippy_lints/src/lib.register_restriction.rs",
-        "clippy_lints/src/lib.register_style.rs",
-        "clippy_lints/src/lib.register_suspicious.rs",
-        "src/docs.rs",
-    ];
-
-    for file in files {
-        remove_file(Path::new(file));
-    }
-
-    if let Ok(docs_dir) = fs::read_dir("src/docs") {
-        for doc_file in docs_dir {
-            let path = doc_file.unwrap().path();
-            remove_file(&path);
-        }
-    }
-
-    if failed {
-        exit_with_failure();
-    }
 }
 
 fn generate_lint_files(
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 18e8bf77225..37e1e6a742f 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index b984132acf5..add73d0aeee 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -2,7 +2,8 @@ use ast::AttrStyle;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast as ast;
 use rustc_errors::Applicability;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute {
     // Separate each crate's features.
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
         if_chain! {
+            if !in_external_macro(cx.sess(), attr.span);
             if cx.tcx.features().lint_reasons;
             if let AttrStyle::Outer = attr.style;
             if let Some(ident) = attr.ident();
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index d74bd57fe45..cfeb75eed3b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -638,7 +638,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.66.0"]
     pub AS_PTR_CAST_MUT,
     nursery,
-    "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+    "casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 7e23318076c..804ae841100 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -141,9 +141,9 @@ fn lint_unnecessary_cast(
 
 fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
     match expr.kind {
-        ExprKind::Lit(ref lit) => Some(lit),
+        ExprKind::Lit(lit) => Some(lit),
         ExprKind::Unary(UnOp::Neg, e) => {
-            if let ExprKind::Lit(ref lit) = e.kind {
+            if let ExprKind::Lit(lit) = e.kind {
                 Some(lit)
             } else {
                 None
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 970f5004993..1c321f46e2d 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
-            // Ignore eq_expr side effects iff one of the expressin kind is a method call
+            // Ignore eq_expr side effects iff one of the expression kind is a method call
             // and the caller is not a mutable, including inner mutable type.
             if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
                 if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index fa726a64937..79d0f6f3607 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::dbg_macro::DBG_MACRO_INFO,
     crate::default::DEFAULT_TRAIT_ACCESS_INFO,
     crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
+    crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,
     crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
     crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
     crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
@@ -249,6 +250,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::MANUAL_FIND_INFO,
     crate::loops::MANUAL_FLATTEN_INFO,
     crate::loops::MANUAL_MEMCPY_INFO,
+    crate::loops::MANUAL_WHILE_LET_SOME_INFO,
     crate::loops::MISSING_SPIN_LOOP_INFO,
     crate::loops::MUT_RANGE_BOUND_INFO,
     crate::loops::NEEDLESS_RANGE_LOOP_INFO,
@@ -445,6 +447,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
     crate::needless_bool::BOOL_COMPARISON_INFO,
     crate::needless_bool::NEEDLESS_BOOL_INFO,
+    crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..e529d81a7e9
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -0,0 +1,72 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
+use hir::{def::Res, ExprKind};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for construction on unit struct using `default`.
+    ///
+    /// ### Why is this bad?
+    /// This adds code complexity and an unnecessary function call.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// #[derive(Default)]
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData::default()
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData
+    /// };
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+    complexity,
+    "unit structs can be contructed without calling `default`"
+}
+declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
+
+impl LateLintPass<'_> for DefaultConstructedUnitStructs {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if_chain!(
+            // make sure we have a call to `Default::default`
+            if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
+            if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
+            if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
+            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // make sure we have a struct with no fields (unit struct)
+            if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
+            if def.is_struct();
+            if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
+            if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+                    expr.span.with_lo(qpath.qself_span().hi()),
+                    "use of `default` to create a unit struct",
+                    "remove this call to `default`",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+            }
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 6615f9c9953..a51a8ee09f6 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -92,10 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
                     if trait_item.id.owner_id.def_id == fn_def_id {
                         // be sure we have `self` parameter in this function
                         if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
-                            trait_self_ty = Some(
-                                TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
-                                    .self_ty(),
-                            );
+                            trait_self_ty =
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
                         }
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index 6fee7fb308c..93bf50fd5e7 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
         let ty = cx.typeck_results().expr_ty(expr);
         if_chain! {
             if let ty::Float(fty) = *ty.kind();
-            if let hir::ExprKind::Lit(ref lit) = expr.kind;
+            if let hir::ExprKind::Lit(lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
             then {
                 let sym_str = sym.as_str();
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index f95b628e6c3..a1a2c398a8a 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -2,9 +2,10 @@ use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // All of these operations are currently not const.
+        // All of these operations are currently not const and are in std.
         if in_constant(cx, expr.hir_id) {
             return;
         }
@@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
         if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
-            if recv_ty.is_floating_point() {
+            if recv_ty.is_floating_point() && !is_no_std_crate(cx) {
                 match path.ident.name.as_str() {
                     "ln" => check_ln1p(cx, expr, receiver),
                     "log" => check_log_base(cx, expr, receiver, args),
@@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
                 }
             }
         } else {
-            check_expm1(cx, expr);
-            check_mul_add(cx, expr);
-            check_custom_abs(cx, expr);
-            check_log_division(cx, expr);
+            if !is_no_std_crate(cx) {
+                check_expm1(cx, expr);
+                check_mul_add(cx, expr);
+                check_custom_abs(cx, expr);
+                check_log_division(cx, expr);
+            }
             check_radians(cx, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index bd66ace4500..10ce2a0f0c7 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
                         );
                     }
 
-                    let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+                    let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
                     if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
                         diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index e5945939e60..b244b913314 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
     };
 
     // Body must be &(mut) <self_data>.name
-    // self_data is not neccessarilly self, to also lint sub-getters, etc…
+    // self_data is not necessarily self, to also lint sub-getters, etc…
 
     let block_expr = if_chain! {
         if let ExprKind::Block(block,_) = body.value.kind;
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ac2d253fe83..ee10334c67f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -252,6 +252,11 @@ declare_clippy_lint! {
     /// A `Result` is at least as large as the `Err`-variant. While we
     /// expect that variant to be seldomly used, the compiler needs to reserve
     /// and move that much memory every single time.
+    /// Furthermore, errors are often simply passed up the call-stack, making
+    /// use of the `?`-operator and its type-conversion mechanics. If the
+    /// `Err`-variant further up the call-stack stores the `Err`-variant in
+    /// question (as library code often does), it itself needs to be at least
+    /// as large, propagating the problem.
     ///
     /// ### Known problems
     /// The size determined by Clippy is platform-dependent.
@@ -330,7 +335,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints when `impl Trait` is being used in a function's paremeters.
+    /// Lints when `impl Trait` is being used in a function's parameters.
     /// ### Why is this bad?
     /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index 57e6caa8711..012aa5a1d1d 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
             if expr1.span.ctxt() == ctxt;
             if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
             if BinOpKind::Add == op1.node;
-            if let ExprKind::Lit(ref lit) = value.kind;
+            if let ExprKind::Lit(lit) = value.kind;
             if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
             if block.expr.is_none();
             then {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 0c7aea6da8f..1e99b6faa6c 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                 // Get the variable name
                 let var_name = ares_path.segments[0].ident.name.as_str();
                 match cond_num_val.kind {
-                    ExprKind::Lit(ref cond_lit) => {
+                    ExprKind::Lit(cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
                             if cx.typeck_results().expr_ty(cond_left).is_signed() {
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index c384172fbde..924a361c0f6 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
+                    if constant(cx, cx.typeck_results(), index).is_some() {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 52d716feea0..b992d689aa9 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
                 span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
             }};
 
-            if matches!(item.kind, ItemKind::Mod(_)) {
-                for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
-                    if_chain! {
-                        if attr.has_name(sym::cfg);
+            if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
+			// Check that it works the same way, the only I way I've found for #10713
+				for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
+					if_chain! {
+						if attr.has_name(sym::cfg);
                         if let Some(mitems) = attr.meta_item_list();
                         if let [mitem] = &*mitems;
                         if mitem.has_name(sym::test);
                         then {
-                            was_test_mod_visited = true;
+							was_test_mod_visited = true;
                             test_mod_span = Some(item.span);
                         }
                     }
                 }
-            }
+			}
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 1b054481371..0ca31033b16 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// It checks for the size of a `Future` created by `async fn` or `async {}`.
     ///
     /// ### Why is this bad?
-    /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
+    /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
     /// large size of a `Future` may cause stack overflows.
     ///
     /// ### Example
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index fec9c6f626c..17bd89efaee 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -532,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
 }
 
 fn is_empty_string(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(lit, _) = lit.node {
             let lit = lit.as_str();
             return lit.is_empty();
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 637b7de920e..16772a9d598 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    None,
-                    "consider adding a type annotation or removing the `let` keyword",
+                    Some(
+						Span::new(local.pat.span.hi(),
+						local.pat.span.hi() + BytePos(1),
+						local.pat.span.ctxt(),
+						local.pat.span.parent()
+					)),
+                    "consider adding a type annotation",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 9e65f9ecd16..3517842a01e 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -94,6 +94,7 @@ mod crate_in_macro_def;
 mod create_dir;
 mod dbg_macro;
 mod default;
+mod default_constructed_unit_structs;
 mod default_instead_of_iter_empty;
 mod default_numeric_fallback;
 mod default_union_representation;
@@ -933,7 +934,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
+    let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
+    store.register_late_pass(move |_| {
+        Box::new(semicolon_block::SemicolonBlock::new(
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        ))
+    });
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
@@ -963,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
+    store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index c87fc4f90e2..d4c3f76b864 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -15,7 +15,7 @@ use rustc_span::symbol::sym;
 use std::fmt::Display;
 use std::iter::Iterator;
 
-/// Checks for for loops that sequentially copy items from one slice-like
+/// Checks for `for` loops that sequentially copy items from one slice-like
 /// object to another.
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
new file mode 100644
index 00000000000..cb9c84be4c7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -0,0 +1,110 @@
+use clippy_utils::{
+    diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
+    match_def_path, paths,
+    source::snippet,
+    SpanlessEq,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::borrow::Cow;
+
+use super::MANUAL_WHILE_LET_SOME;
+
+/// The kind of statement that the `pop()` call appeared in.
+///
+/// Depending on whether the value was assigned to a variable or not changes what pattern
+/// we use for the suggestion.
+#[derive(Copy, Clone)]
+enum PopStmt<'hir> {
+    /// `x.pop().unwrap()` was and assigned to a variable.
+    /// The pattern of this local variable will be used and the local statement
+    /// is deleted in the suggestion.
+    Local(&'hir Pat<'hir>),
+    /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable.
+    /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression
+    /// is replaced with that identifier.
+    Anonymous,
+}
+
+fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) {
+    span_lint_and_then(
+        cx,
+        MANUAL_WHILE_LET_SOME,
+        pop_span,
+        "you seem to be trying to pop elements from a `Vec` in a loop",
+        |diag| {
+            let (pat, pop_replacement) = match pop_stmt_kind {
+                PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()),
+                PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()),
+            };
+
+            let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
+            multispan_sugg_with_applicability(
+                diag,
+                "consider using a `while..let` loop",
+                Applicability::MachineApplicable,
+                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
+            );
+        },
+    );
+}
+
+fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
+    if let ExprKind::MethodCall(..) = expr.kind
+        && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    {
+        match_def_path(cx, id, method)
+    } else {
+        false
+    }
+}
+
+fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
+    if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
+        && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
+        && match_method_call(cx, unwrap_recv, &paths::VEC_POP)
+        && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
+    {
+        // make sure they're the same `Vec`
+        SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv)
+    } else {
+        false
+    }
+}
+
+fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Local(local) = stmt.kind
+        && let Some(init) = local.init
+        && is_vec_pop_unwrap(cx, init, is_empty_recv)
+    {
+        report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span);
+    }
+}
+
+fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
+        if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
+            let offending_arg = args
+                .iter()
+                .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
+
+            if let Some(offending_arg) = offending_arg {
+                report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
+            }
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
+    if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
+        && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
+        && match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
+        && let ExprKind::Block(body, _) = body.kind
+        && let Some(stmt) = body.stmts.first()
+    {
+        check_local(cx, stmt, is_empty_recv, loop_span);
+        check_call_arguments(cx, stmt, is_empty_recv, loop_span);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 610a0233eee..f83ad388a74 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -7,6 +7,7 @@ mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
+mod manual_while_let_some;
 mod missing_spin_loop;
 mod mut_range_bound;
 mod needless_range_loop;
@@ -575,6 +576,36 @@ declare_clippy_lint! {
     "manual implementation of `Iterator::find`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
+    /// in the body as a separate operation.
+    ///
+    /// ### Why is this bad?
+    /// Such loops can be written in a more idiomatic way by using a while-let loop and directly
+    /// pattern matching on the return value of `Vec::pop()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while !numbers.is_empty() {
+    ///     let number = numbers.pop().unwrap();
+    ///     // use `number`
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while let Some(number) = numbers.pop() {
+    ///     // use `number`
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MANUAL_WHILE_LET_SOME,
+    style,
+    "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
+}
+
 declare_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
@@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
     MANUAL_FIND,
+    MANUAL_WHILE_LET_SOME
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
+        if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
             missing_spin_loop::check(cx, condition, body);
+            manual_while_let_some::check(cx, condition, body, span);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 5c317c2a5bb..cb446567506 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>(
     indexed_ty: Ty<'tcx>,
 ) -> bool {
     if_chain! {
-        if let ExprKind::Lit(ref lit) = end.kind;
+        if let ExprKind::Lit(lit) = end.kind;
         if let ast::LitKind::Int(end_int, _) = lit.node;
         if let ty::Array(_, arr_len_const) = indexed_ty.kind();
         if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index ce5d657bcf0..45ea5aab4c2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             };
             let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
             let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
-            // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+            // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
             span_lint_and_then(
                 cx,
                 MANUAL_ASSERT,
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 98e698c6c2a..1247370b74a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                 if source != MatchSource::Normal {
                     return;
                 }
-                // Any other number than two arms doesn't (neccessarily)
+                // Any other number than two arms doesn't (necessarily)
                 // have a trivial mapping to let else.
                 if arms.len() != 2 {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 72cdb9c1736..5259066eb71 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.64.0"]
     pub MANUAL_RETAIN,
     perf,
-    "`retain()` is simpler and the same functionalitys"
+    "`retain()` is simpler and the same functionalities"
 }
 
 pub struct ManualRetain {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
index df1e585f10b..69105ff0d5c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
                 if arms.len() == 2 {
                     // no guards
                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
+                        if let ExprKind::Lit(lit) = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
                                 LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 158e6caa4de..a48f4c77f85 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -284,6 +284,7 @@ impl<'a> NormalizedPat<'a> {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
                     LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
+                    LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
                     LitKind::Bool(val) => Self::LitBool(val),
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 7b609ff3df8..af121f317cd 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>(
     // Determine which function should be used, and the type contained by the corresponding
     // variant.
     let (good_method, inner_ty) = match check_pat.kind {
-        PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
-            if let PatKind::Wild = sub_pat.kind {
+        PatKind::TupleStruct(ref qpath, args, rest) => {
+            let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
+            let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
+
+            if is_wildcard || is_rest {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
                 let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
@@ -334,7 +337,7 @@ fn find_good_method_for_match<'a>(
     };
 
     match body_node_pair {
-        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+        (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
             (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
             (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
             _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 27a05337a29..8984b2cf8fd 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -18,7 +18,7 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Lit(ref lit) = info.other.kind;
+        if let hir::ExprKind::Lit(lit) = info.other.kind;
         if let ast::LitKind::Char(c) = lit.node;
         then {
             let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
index 83c1bf20346..e2029da8081 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::Range::hir(index_expr);
-            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
+            if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 23d23f25f14..bd625a6914c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -42,11 +42,11 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
             let argument_option = match arguments[0].kind {
-                ExprKind::Lit(ref span) => {
+                ExprKind::Lit(span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
                         ..
-                    } = *span
+                    } = span
                     {
                         if *lit { Argument::True } else { Argument::False }
                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
index e3f2de3cd46..0284d9dea30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
-        if let ExprKind::Lit(ref lit) = arg.kind;
+        if let ExprKind::Lit(lit) = arg.kind;
         if let LitKind::Str(ref path_lit, _) = lit.node;
         if let pushed_path = Path::new(path_lit.as_str());
         if let Some(pushed_path_lit) = pushed_path.to_str();
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index 361a3082f94..c028e954381 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
         // check if argument of `SeekFrom::Current` is `0`
         if args.len() == 1 &&
-            let ExprKind::Lit(ref lit) = args[0].kind &&
+            let ExprKind::Lit(lit) = args[0].kind &&
             let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
             return true
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 660b7049cce..787e9e0ebd2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
         match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
         args1.len() == 1 &&
-        let ExprKind::Lit(ref lit) = args1[0].kind &&
+        let ExprKind::Lit(lit) = args1[0].kind &&
         let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
     {
         let method_call_span = expr.span.with_lo(name_span.lo());
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index aa87dead38f..5a3d12fd790 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -78,7 +78,7 @@ pub(super) fn check(
     }
 
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = init.kind {
+    if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index e99081ad062..1adecd2caac 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
     /// Checks if a provided method is used implicitly by a trait
     /// implementation. A usage example would be a wrapper where every method
     /// should perform some operation before delegating to the inner type's
-    /// implemenation.
+    /// implementation.
     ///
     /// This lint should typically be enabled on a specific trait `impl` item
     /// rather than globally.
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index c87059bf61d..71281a0b40b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -3,10 +3,12 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
+use clippy_utils::{
+    get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+};
+use clippy_utils::{higher, SpanlessEq};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
@@ -77,7 +79,39 @@ declare_clippy_lint! {
     "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 }
 
-declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions of the form `if c { x = true } else { x = false }`
+    /// (or vice versa) and suggest assigning the variable directly from the
+    /// condition.
+    ///
+    /// ### Why is this bad?
+    /// Redundant code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// if must_keep(x, y) {
+    ///     skip = false;
+    /// } else {
+    ///     skip = true;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// skip = !must_keep(x, y);
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub NEEDLESS_BOOL_ASSIGN,
+    complexity,
+    "setting the same boolean variable in both branches of an if-statement"
+}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]);
 
 fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     let mut inner = e;
@@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     _ => (),
                 }
             }
+            if let Some((lhs_a, a)) = fetch_assign(then) &&
+                let Some((lhs_b, b)) = fetch_assign(r#else) &&
+                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
+                span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
+            {
+                let mut applicability = Applicability::MachineApplicable;
+                let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
+                let sugg = if a == b {
+                    format!("{cond}; {lhs} = {a:?};")
+                } else {
+                    format!("{lhs} = {};", if a { cond } else { !cond })
+                };
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_BOOL_ASSIGN,
+                    e.span,
+                    "this if-then-else expression assigns a bool literal",
+                    "you can reduce it to",
+                    sugg,
+                    applicability
+                );
+            }
         }
     }
 }
@@ -369,10 +426,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
 }
 
 fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
-    if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+    if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
         if let LitKind::Bool(value) = lit_ptr.node {
             return Some(value);
         }
     }
     None
 }
+
+fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> {
+    if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind {
+        fetch_bool_expr(rhs).map(|b| (lhs, b))
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index 6e54b243c03..da1b9d99931 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -49,14 +49,14 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
 
 fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
     if is_start &&
-    let ExprKind::Lit(ref literal) = e.kind &&
+    let ExprKind::Lit(literal) = e.kind &&
     let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
     {
         // don't check floating point literals on the start expression of a range
         return;
     }
     if_chain! {
-        if let ExprKind::Lit(ref literal) = e.kind;
+        if let ExprKind::Lit(literal) = e.kind;
         // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
         if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
         // inspect the source code of the expression for parenthesis
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index ed3e2c6e7f4..db0e22842d1 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Lit(ref l) = lit.kind;
+        if let ExprKind::Lit(l) = lit.kind;
         if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
         if cx.typeck_results().expr_ty(exp).is_integral();
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index fafcf257094..f72595987ee 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -110,7 +110,7 @@ impl ArithmeticSideEffects {
     /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
     fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
         let actual = peel_hir_expr_unary(expr).0;
-        if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
+        if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             return Some(n)
         }
         if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 9e6c6c73d4f..b8b32df6cc6 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -180,7 +180,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
         .allow_invalid_utf8(!utf8)
         .build();
 
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
             let r = r.as_str();
             let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 34a3e5ddf4f..419d7991f0e 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
     restriction,
     "add a semicolon outside the block"
 }
-declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+#[derive(Copy, Clone)]
+pub struct SemicolonBlock {
+    semicolon_inside_block_ignore_singleline: bool,
+    semicolon_outside_block_ignore_multiline: bool,
+}
+
+impl SemicolonBlock {
+    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+        Self {
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        }
+    }
+
+    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+        let insert_span = tail.span.source_callsite().shrink_to_hi();
+        let remove_span = semi_span.with_lo(block.span.hi());
+
+        if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_INSIDE_BLOCK,
+            semi_span,
+            "consider moving the `;` inside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+
+    fn semicolon_outside_block(
+        self,
+        cx: &LateContext<'_>,
+        block: &Block<'_>,
+        tail_stmt_expr: &Expr<'_>,
+        semi_span: Span,
+    ) {
+        let insert_span = block.span.with_lo(block.span.hi());
+        // account for macro calls
+        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_OUTSIDE_BLOCK,
+            block.span,
+            "consider moving the `;` outside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+}
 
 impl LateLintPass<'_> for SemicolonBlock {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
                     span,
                     ..
                 } = stmt else { return };
-                semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr, span);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
                 ..
-            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            }) if !block.span.from_expansion() => {
+                self.semicolon_inside_block(cx, block, tail, stmt.span);
+            },
             _ => (),
         }
     }
 }
 
-fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
-    let insert_span = tail.span.source_callsite().shrink_to_hi();
-    let remove_span = semi_span.with_lo(block.span.hi());
+fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
+    if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
+        return Some(line.line);
+    }
 
-    span_lint_and_then(
-        cx,
-        SEMICOLON_INSIDE_BLOCK,
-        semi_span,
-        "consider moving the `;` inside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
-}
-
-fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
-    let insert_span = block.span.with_lo(block.span.hi());
-    // account for macro calls
-    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
-
-    span_lint_and_then(
-        cx,
-        SEMICOLON_OUTSIDE_BLOCK,
-        block.span,
-        "consider moving the `;` outside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
+    None
 }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index ae7d19624ba..993f9373d85 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
-        if pat.span.desugaring_kind().is_some() {
+        if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index a2109038a05..858135c8d46 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -74,7 +74,7 @@ enum InitializationType<'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
+        // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index b2f4b310915..5b588e914fd 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
+            if !in_external_macro(cx.sess(), e.span);
             if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
             if let ExprKind::Lit(lit) = &receiver.kind;
diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
index 03324c66e8e..2f2e84fa35a 100644
--- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
 use clippy_utils::{get_parent_node, match_libc_symbol};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
                 let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
                 let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
                     "as_bytes"
-                } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+                } else if is_type_lang_item(cx, ty, LangItem::CStr) {
                     "to_bytes"
                 } else {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index 98f5b47f7a0..bb9da3a2047 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
         if let Some(last_field) = data.fields().last();
         if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
-        // Then check if that that array zero-sized
+        // Then check if that array is zero-sized
         let length = Const::from_anon_const(cx.tcx, length.def_id);
         let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
         if let Some(length) = length;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index c6834a8fdaa..3c873a5901d 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -90,8 +90,8 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// `Option<_>` represents an optional value. `Option<Option<_>>`
-    /// represents an optional optional value which is logically the same thing as an optional
-    /// value but has an unneeded extra level of wrapping.
+    /// represents an optional value which itself wraps an optional. This is logically the
+    /// same thing as an optional value but has an unneeded extra level of wrapping.
     ///
     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
     /// consider a custom `enum` instead, with clear names for each case.
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index 8980283e5c8..e275bfd37b0 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let ExprKind::Lit(ref lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind {
             if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
                 check_str(cx, lit.span, expr.hir_id);
             }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index af1c8d83b4f..e7449639f3a 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -109,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         // Ignore implementations of traits, because the lint should be on the
-        // trait, not on the implmentation of it.
+        // trait, not on the implementation of it.
         let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
         let ItemKind::Impl(parent) = parent.kind else { return };
         if parent.of_trait.is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 01927b6b5f1..935ea90d245 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -304,6 +304,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("ByteStr(ref {vec})");
                 chain!(self, "let [{:?}] = **{vec}", vec.value);
             },
+            LitKind::CStr(ref vec, _) => {
+                bind!(self, vec);
+                kind!("CStr(ref {vec})");
+                chain!(self, "let [{:?}] = **{vec}", vec.value);
+            }
             LitKind::Str(s, _) => {
                 bind!(self, s);
                 kind!("Str({s}, _)");
@@ -333,7 +338,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     #[allow(clippy::too_many_lines)]
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
+        if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
             chain!(
                 self,
@@ -561,7 +566,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::OffsetOf(container, ref fields) => {
                 bind!(self, container, fields);
                 kind!("OffsetOf({container}, {fields})");
-            }
+            },
             ExprKind::Struct(qpath, fields, base) => {
                 bind!(self, qpath, fields);
                 opt_bind!(self, base);
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 67bb499c455..5f05d971fce 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -277,6 +277,14 @@ define_Conf! {
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
     (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Lint: SEMICOLON_INSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's multiline.
+    (semicolon_inside_block_ignore_singleline: bool = false),
+    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's singleline.
+    (semicolon_outside_block_ignore_multiline: bool = false),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 124ebd164e6..66a5079fa85 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index d3a6929f67e..9edaae85373 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -117,7 +117,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
-        ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+        ExprKind::Lit(lit) => lit_search_pat(&lit.node),
         ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
         ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
         ExprKind::Call(first, [.., last])
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 99bfc4b5717..8075881e3bb 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -211,6 +211,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
         LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
+        LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
@@ -324,7 +325,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
             ExprKind::Block(block, _) => self.block(block),
-            ExprKind::Lit(ref lit) => {
+            ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 50bef370930..a61e4c38088 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -311,6 +311,8 @@ pub struct While<'hir> {
     pub condition: &'hir Expr<'hir>,
     /// `while` loop body
     pub body: &'hir Expr<'hir>,
+    /// Span of the loop header
+    pub span: Span,
 }
 
 impl<'hir> While<'hir> {
@@ -336,10 +338,10 @@ impl<'hir> While<'hir> {
             },
             _,
             LoopSource::While,
-            _,
+            span,
         ) = expr.kind
         {
-            return Some(Self { condition, body });
+            return Some(Self { condition, body, span });
         }
         None
     }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d972ed82c25..9b7408d5133 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -301,7 +301,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
             (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
-            (&ExprKind::OffsetOf(l_container, ref l_fields), &ExprKind::OffsetOf(r_container, ref r_fields)) => {
+            (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
                 self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
             },
             _ => false,
@@ -718,7 +718,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_pat(pat);
             },
             ExprKind::Err(_) => {},
-            ExprKind::Lit(ref l) => {
+            ExprKind::Lit(l) => {
                 l.node.hash(&mut self.s);
             },
             ExprKind::Loop(b, ref i, ..) => {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6b677df4641..964104fc31d 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -86,10 +86,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
-    Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
+    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
+    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
     MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -197,31 +197,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
 /// }
 /// ```
 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
-    match cx.tcx.hir().get_by_def_id(parent_id) {
-        Node::Item(&Item {
-            kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
-            ..
-        })
-        | Node::TraitItem(&TraitItem {
-            kind: TraitItemKind::Const(..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Const(..),
-            ..
-        })
-        | Node::AnonConst(_) => true,
-        Node::Item(&Item {
-            kind: ItemKind::Fn(ref sig, ..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Fn(ref sig, _),
-            ..
-        }) => sig.header.constness == Constness::Const,
-        _ => false,
-    }
+    cx.tcx.hir().is_inside_const_context(id)
 }
 
 /// Checks if a `Res` refers to a constructor of a `LangItem`
@@ -846,7 +822,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         },
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
         ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
-            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
+            if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind;
             if let LitKind::Int(v, _) = const_lit.node;
             if v <= 32 && is_default_equivalent(cx, x);
             then {
@@ -875,7 +851,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
             }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
             ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
             ExprKind::Repeat(_, ArrayLen::Body(len)) => {
-                if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
+                if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
                     let LitKind::Int(v, _) = const_lit.node
                 {
                         return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
@@ -1569,7 +1545,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
 /// Checks whether the given expression is a constant literal of the given value.
 pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
     // FIXME: use constant folding
-    if let ExprKind::Lit(ref spanned) = expr.kind {
+    if let ExprKind::Lit(spanned) = expr.kind {
         if let LitKind::Int(v, _) = spanned.node {
             return v == value;
         }
@@ -2165,10 +2141,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
         .predicates
         .iter()
         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-    traits::impossible_predicates(
-        cx.tcx,
-        traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>(),
-    )
+    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
 }
 
 /// Returns the `DefId` of the callee if the given expression is a function or method call.
@@ -2233,8 +2206,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     None
 }
 
-/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
-/// `hash` must be comformed with `eq`
+/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
+/// and `a` is before `b` in `exprs` for all `a` and `b` in
+/// `exprs`
+///
+/// Given functions `eq` and `hash` such that `eq(a, b) == true`
+/// implies `hash(a) == hash(b)`
 pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 where
     Hash: Fn(&T) -> u64,
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 62d388a5ece..e4a4936ff42 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -362,7 +362,7 @@ thread_local! {
     /// able to access the many features of a [`LateContext`].
     ///
     /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
-    /// assumption that the early pass the populates the map and the later late passes will all be
+    /// assumption that the early pass that populates the map and the later late passes will all be
     /// running on the same thread.
     static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = {
         static CALLED: AtomicBool = AtomicBool::new(false);
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 9be2d0eae80..0f0792fdaa9 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -159,3 +159,7 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
 pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
 pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
+pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
+pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
+pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
+pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index ecd712f32dc..c0d2c835d63 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -194,7 +194,9 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
+        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => {
+            Ok(())
+        },
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 03cd8e48b9a..14f7f03016f 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -162,7 +162,7 @@ impl<'a> Sugg<'a> {
                 get_snippet(lhs.span),
                 get_snippet(rhs.span),
             ),
-            hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
+            hir::ExprKind::Cast(lhs, ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
         }
@@ -254,11 +254,7 @@ impl<'a> Sugg<'a> {
                 snippet_with_context(cx, lhs.span, ctxt, default, app).0,
                 snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
-            ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
-                AssocOp::As,
-                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
-                snippet_with_context(cx, ty.span, ctxt, default, app).0,
-            ),
+            ast::ExprKind::Cast(ref lhs, ref ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
                 AssocOp::As,
@@ -603,8 +599,8 @@ enum Associativity {
 #[must_use]
 fn associativity(op: AssocOp) -> Associativity {
     use rustc_ast::util::parser::AssocOp::{
-        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater,
-        GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
+        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd,
+        LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
     };
 
     match op {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a6572011644..7b4ed77e8ed 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -93,7 +93,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                            // and check substituions to find `U`.
+                            // and check substitutions to find `U`.
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
                                 if trait_predicate
                                     .trait_ref
@@ -837,7 +837,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Adt(adt, _) = ty.kind()
         && let &[krate, .., name] = &*cx.get_def_path(adt.did())
         && let sym::libc | sym::core | sym::std = krate
-        && name.as_str() == "c_void"
+        && name == rustc_span::sym::c_void
     {
         true
     } else {
@@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>(
 ///
 /// This function is for associated types which are "known" to be valid with the given
 /// substitutions, and as such, will only return `None` when debug assertions are disabled in order
-/// to prevent ICE's. With debug assertions enabled this will check that that type normalization
+/// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index bd26f4fc913..139102798c4 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md
index faf3ce9093a..37cc0453809 100644
--- a/src/tools/clippy/lintcheck/README.md
+++ b/src/tools/clippy/lintcheck/README.md
@@ -79,9 +79,11 @@ is explicitly specified in the options.
 
 ### Fix mode
 You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
-print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).  
+print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). 
 This lets us spot bad suggestions or false positives automatically in some cases.  
 
+> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can.
+
 Please note that the target dir should be cleaned afterwards since clippy will modify
 the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.
 
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 23c85298027..03d1877d6c6 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -421,7 +421,7 @@ impl Crate {
             {
                 let subcrate = &stderr[63..];
                 println!(
-                    "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
+                    "ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}",
                     self.name
                 );
             }
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 91e8ccea1f4..60b8a5ac071 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-04-06"
+channel = "nightly-2023-05-05"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 205905d5091..59bf447a7cd 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -11,7 +11,6 @@
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 extern crate rustc_driver;
-extern crate rustc_errors;
 extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
@@ -20,13 +19,10 @@ use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
 
-use std::borrow::Cow;
 use std::env;
 use std::ops::Deref;
-use std::panic;
 use std::path::Path;
 use std::process::exit;
-use std::sync::LazyLock;
 
 /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
@@ -198,66 +194,18 @@ You can use tool lints to allow or deny lints from your code, eg.:
 
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
 
-type PanicCallback = dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static;
-static ICE_HOOK: LazyLock<Box<PanicCallback>> = LazyLock::new(|| {
-    let hook = panic::take_hook();
-    panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
-    hook
-});
-
-fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
-    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
-    (*ICE_HOOK)(info);
-
-    // Separate the output with an empty line
-    eprintln!();
-
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
-    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
-        rustc_errors::ColorConfig::Auto,
-        None,
-        None,
-        fallback_bundle,
-        false,
-        false,
-        None,
-        false,
-        false,
-        rustc_errors::TerminalUrl::No,
-    ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
-
-    // a .span_bug or .bug call has already printed what
-    // it wants to print.
-    if !info.payload().is::<rustc_errors::ExplicitBug>() {
-        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
-        handler.emit_diagnostic(&mut d);
-    }
-
-    let version_info = rustc_tools_util::get_version_info!();
-
-    let xs: Vec<Cow<'static, str>> = vec![
-        "the compiler unexpectedly panicked. this is a bug.".into(),
-        format!("we would appreciate a bug report: {bug_report_url}").into(),
-        format!("Clippy version: {version_info}").into(),
-    ];
-
-    for note in &xs {
-        handler.note_without_error(note.as_ref());
-    }
-
-    // If backtraces are enabled, also print the query stack
-    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
-
-    let num_frames = if backtrace { None } else { Some(2) };
-
-    interface::try_print_query_stack(&handler, num_frames);
-}
-
 #[allow(clippy::too_many_lines)]
 pub fn main() {
     rustc_driver::init_rustc_env_logger();
-    LazyLock::force(&ICE_HOOK);
+
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
+        // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
+        // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
+        // accept a generic closure.
+        let version_info = rustc_tools_util::get_version_info!();
+        handler.note_without_error(format!("Clippy version: {version_info}"));
+    });
+
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
         let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index c5e9b96cf3f..188ff87abfc 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -13,7 +13,7 @@ Usage:
 
 Common options:
     --no-deps                Run Clippy only on the given crate, without linting the dependencies
-    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
+    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
     -h, --help               Print this message
     -V, --version            Print version info and exit
     --explain LINT           Print the documentation for a given lint
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 68a878e9a3d..afde31face1 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -39,7 +39,7 @@ fn dogfood_clippy() {
     assert!(
         failed_packages.is_empty(),
         "Dogfood failed for packages `{}`",
-        failed_packages.iter().format(", "),
+        failed_packages.iter().join(", "),
     );
 }
 
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed
new file mode 100644
index 00000000000..fc8038a0907
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs
new file mode 100644
index 00000000000..52ce1f0387e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr
new file mode 100644
index 00000000000..2f58842eab0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr
@@ -0,0 +1,55 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:43:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:44:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/both.rs:49:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:63:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml
new file mode 100644
index 00000000000..4d03e88deba
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml
@@ -0,0 +1,2 @@
+semicolon-inside-block-ignore-singleline = true
+semicolon-outside-block-ignore-multiline = true
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
new file mode 100644
index 00000000000..23df9830177
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
new file mode 100644
index 00000000000..e8516f79b20
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
new file mode 100644
index 00000000000..2569dc4b4e4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
@@ -0,0 +1,18 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
new file mode 100644
index 00000000000..7e9055e7110
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
new file mode 100644
index 00000000000..4dc956d8a4b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
new file mode 100644
index 00000000000..6dd3577dd09
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
@@ -0,0 +1,39 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 36b372b36f4..44710b09648 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           semicolon-inside-block-ignore-singleline
+           semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
            standard-macro-braces
            suppress-restriction-lint-in-const
diff --git a/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs
new file mode 100644
index 00000000000..5c3407628be
--- /dev/null
+++ b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::allow_attributes)]
+#![feature(lint_reasons)]
+#![crate_type = "proc-macro"]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index a9bb61451dc..e5bb906663c 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -21,6 +21,13 @@ macro_rules! string_add {
     };
 }
 
+#[macro_export]
+macro_rules! string_lit_as_bytes {
+    ($s:literal) => {
+        const C: &[u8] = $s.as_bytes();
+    };
+}
+
 #[macro_export]
 macro_rules! mut_mut {
     () => {
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index 92c47b41a38..d164dd0e545 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
                     elided += 1;
 
                     // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
-                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // In order to avoid adding the dependency, get a default span from a nonexistent token.
                     // A default span is needed to mark the code as coming from expansion.
                     let span = Star::default().span();
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
index 9831c3373d4..fbb10a133e2 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -79,6 +79,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
index 5e3047bb32c..709a18d63e4 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -111,6 +111,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
index 5cfb75cc0df..3bdae75cad2 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -98,7 +98,7 @@ LL | |     };
    = note: `!b as i32` or `(!b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> $DIR/bool_to_int_with_if.rs:119:5
+  --> $DIR/bool_to_int_with_if.rs:126:5
    |
 LL |     if a { 1 } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
index 6afce208769..e6331290420 100644
--- a/src/tools/clippy/tests/ui/box_default.fixed
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index 09365618e63..34a05a29c5a 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index 78e17b9f035..c9834863601 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -1,5 +1,5 @@
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:22:32
+  --> $DIR/box_default.rs:23:32
    |
 LL |     let _string: Box<String> = Box::new(Default::default());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
@@ -7,91 +7,91 @@ LL |     let _string: Box<String> = Box::new(Default::default());
    = note: `-D clippy::box-default` implied by `-D warnings`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:23:17
+  --> $DIR/box_default.rs:24:17
    |
 LL |     let _byte = Box::new(u8::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:24:16
+  --> $DIR/box_default.rs:25:16
    |
 LL |     let _vec = Box::new(Vec::<u8>::new());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:25:17
+  --> $DIR/box_default.rs:26:17
    |
 LL |     let _impl = Box::new(ImplementsDefault::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:26:18
+  --> $DIR/box_default.rs:27:18
    |
 LL |     let _impl2 = Box::new(<ImplementsDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:27:42
+  --> $DIR/box_default.rs:28:42
    |
 LL |     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:29:28
+  --> $DIR/box_default.rs:30:28
    |
 LL |     let _in_macro = outer!(Box::new(String::new()));
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:30:34
+  --> $DIR/box_default.rs:31:34
    |
 LL |     let _string_default = outer!(Box::new(String::from("")));
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:31:46
+  --> $DIR/box_default.rs:32:46
    |
 LL |     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
    |                                              ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:32:33
+  --> $DIR/box_default.rs:33:33
    |
 LL |     let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:33:25
+  --> $DIR/box_default.rs:34:25
    |
 LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:35:16
+  --> $DIR/box_default.rs:36:16
    |
 LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:40:5
+  --> $DIR/box_default.rs:41:5
    |
 LL |     Box::new(bool::default())
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:57:28
+  --> $DIR/box_default.rs:58:28
    |
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:66:17
+  --> $DIR/box_default.rs:67:17
    |
 LL |         let _ = Box::new(WeirdPathed::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:78:18
+  --> $DIR/box_default.rs:79:18
    |
 LL |             Some(Box::new(Foo::default()))
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
diff --git a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
index 24d7eb28a19..b77f01883bf 100644
--- a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs
@@ -23,7 +23,7 @@ fn main() {
         r_x as *const [i32]
     } as *const [u8];
 
-    // Check that resores of the same size are detected through blocks
+    // Check that resources of the same size are detected through blocks
     let restore_block_1 = { r_x as *const [i32] } as *const [u8] as *const [u32];
     let restore_block_2 = { ({ r_x as *const [i32] }) as *const [u8] } as *const [u32];
     let restore_block_3 = {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.rs b/src/tools/clippy/tests/ui/crashes/ice-10645.rs
new file mode 100644
index 00000000000..4d8698d383b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-10645.rs
@@ -0,0 +1,7 @@
+// compile-flags: --cap-lints=warn
+// https://github.com/rust-lang/rust-clippy/issues/10645
+
+#![warn(clippy::future_not_send)]
+pub async fn bar<'a, T: 'a>(_: T) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.stderr b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
similarity index 89%
rename from src/tools/clippy/tests/ui/crashes/ice-5207.stderr
rename to src/tools/clippy/tests/ui/crashes/ice-10645.stderr
index 59146c23e0d..fc084e30d7f 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5207.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
@@ -1,11 +1,11 @@
 error: future cannot be sent between threads safely
-  --> $DIR/ice-5207.rs:6:35
+  --> $DIR/ice-10645.rs:5:35
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                                   ^ future returned by `bar` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/ice-5207.rs:6:29
+  --> $DIR/ice-10645.rs:5:29
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                             ^ has type `T` which is not `Send`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
index 893c15f5d73..0df8b88fea2 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs
@@ -1,8 +1,4 @@
-// compile-flags: --cap-lints=warn
-// ^ for https://github.com/rust-lang/rust-clippy/issues/10645
-
 // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
-#![warn(clippy::future_not_send)]
 pub async fn bar<'a, T: 'a>(_: T) {}
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
rename to src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
new file mode 100644
index 00000000000..4c2d1ea48e1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData,
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>;
+    let _: PhantomData<i32> = PhantomData;
+    let _ = UnitStruct;
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..850793dd5de
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self::default()
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData::default(),
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>::default();
+    let _: PhantomData<i32> = PhantomData::default();
+    let _ = UnitStruct::default();
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
new file mode 100644
index 00000000000..4058943d087
--- /dev/null
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
@@ -0,0 +1,34 @@
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:13:13
+   |
+LL |         Self::default()
+   |             ^^^^^^^^^^^ help: remove this call to `default`
+   |
+   = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:55:31
+   |
+LL |             inner: PhantomData::default(),
+   |                               ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:106:33
+   |
+LL |     let _ = PhantomData::<usize>::default();
+   |                                 ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:107:42
+   |
+LL |     let _: PhantomData<i32> = PhantomData::default();
+   |                                          ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:108:23
+   |
+LL |     let _ = UnitStruct::default();
+   |                       ^^^^^^^^^^^ help: remove this call to `default`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
new file mode 100644
index 00000000000..a42c6383cce
--- /dev/null
+++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs
@@ -0,0 +1,31 @@
+#![feature(lang_items, start)]
+#![warn(clippy::imprecise_flops)]
+#![warn(clippy::suboptimal_flops)]
+#![no_std]
+
+// The following should not lint, as the suggested methods {f32,f64}.mul_add()
+// and {f32,f64}::abs() are not available in no_std
+
+pub fn mul_add() {
+    let a: f64 = 1234.567;
+    let b: f64 = 45.67834;
+    let c: f64 = 0.0004;
+    let _ = a * b + c;
+}
+
+fn fake_abs1(num: f64) -> f64 {
+    if num >= 0.0 { num } else { -num }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed
index fc6d937060d..d18f9387565 100644
--- a/src/tools/clippy/tests/ui/from_over_into.fixed
+++ b/src/tools/clippy/tests/ui/from_over_into.fixed
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl From<X> for SelfKeywords {
     fn from(val: X) -> Self {
-        let _ = X::default();
+        let _ = X;
         let _ = X::FOO;
         let _: X = val;
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs
index fe1ebee35f1..de8ff0b06bd 100644
--- a/src/tools/clippy/tests/ui/from_over_into.rs
+++ b/src/tools/clippy/tests/ui/from_over_into.rs
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl Into<SelfKeywords> for X {
     fn into(self) -> SelfKeywords {
-        let _ = Self::default();
+        let _ = Self;
         let _ = Self::FOO;
         let _: Self = self;
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index 3c4d011d6fb..6039f86fe67 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -5,7 +5,7 @@ LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::from-over-into` implied by `-D warnings`
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for StringWrapper {
 LL ~     fn from(val: String) -> Self {
@@ -18,7 +18,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for SelfType {
 LL ~     fn from(val: String) -> Self {
@@ -31,11 +31,11 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<X>`
+help: replace the `Into` implementation with `From<X>`
    |
 LL ~ impl From<X> for SelfKeywords {
 LL ~     fn from(val: X) -> Self {
-LL ~         let _ = X::default();
+LL ~         let _ = X;
 LL ~         let _ = X::FOO;
 LL ~         let _: X = val;
    |
@@ -48,7 +48,7 @@ LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-help: replace the `Into` implentation with `From<ExplicitPaths>`
+help: replace the `Into` implementation with `From<ExplicitPaths>`
    |
 LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
 LL ~     fn from(mut val: crate::ExplicitPaths) -> Self {
@@ -64,7 +64,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
+help: replace the `Into` implementation with `From<std::vec::Vec<T>>`
    |
 LL ~     impl<T> From<Vec<T>> for FromOverInto<T> {
 LL ~         fn from(val: Vec<T>) -> Self {
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
index 6f6ce351921..251f1d84e74 100644
--- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
@@ -4,7 +4,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<InMacro> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<std::string::String>`
+   = help: replace the `Into` implementation with `From<std::string::String>`
    = note: `-D clippy::from-over-into` implied by `-D warnings`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
@@ -13,7 +13,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<WeirdUpperSelf> for &'static [u8] {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<&'static [u8]>`
+   = help: replace the `Into` implementation with `From<&'static [u8]>`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
   --> $DIR/from_over_into_unfixable.rs:28:1
@@ -23,7 +23,7 @@ LL | impl Into<u8> for ContainsVal {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-   = help: replace the `Into` implentation with `From<ContainsVal>`
+   = help: replace the `Into` implementation with `From<ContainsVal>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs
similarity index 100%
rename from src/tools/clippy/tests/ui/items_after_test_module.rs
rename to src/tools/clippy/tests/ui/items_after_test_module/block_module.rs
diff --git a/src/tools/clippy/tests/ui/items_after_test_module.stderr b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
similarity index 89%
rename from src/tools/clippy/tests/ui/items_after_test_module.stderr
rename to src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
index 8f1616dabc1..597f1b9510c 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module.stderr
+++ b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
@@ -1,5 +1,5 @@
 error: items were found after the testing module
-  --> $DIR/items_after_test_module.rs:13:1
+  --> $DIR/block_module.rs:13:1
    |
 LL | / mod tests {
 LL | |     #[test]
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs
new file mode 100644
index 00000000000..6a757aef48e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs
@@ -0,0 +1,20 @@
+//@compile-flags: --test
+#![allow(unused)]
+#![warn(clippy::items_after_test_module)]
+
+// Nothing here should lint, as `tests` is an imported module (that has no body).
+
+fn main() {}
+
+fn should_not_lint() {}
+
+#[path = "auxiliary/tests.rs"]
+#[cfg(test)]
+mod tests; // Should not lint
+
+fn should_not_lint2() {}
+
+const SHOULD_ALSO_NOT_LINT: usize = 1;
+macro_rules! should_not_lint {
+    () => {};
+}
diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
index 47e76ea1d04..6844cb998f7 100644
--- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr
@@ -4,7 +4,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = a();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:36:10
+   |
+LL |     let _ = a();
+   |          ^
    = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
 
 error: non-binding `let` without a type annotation
@@ -13,7 +17,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = b(1);
    |     ^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:37:10
+   |
+LL |     let _ = b(1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:39:5
@@ -21,7 +29,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = d(&1);
    |     ^^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:39:10
+   |
+LL |     let _ = d(&1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:40:5
@@ -29,7 +41,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = e();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:40:10
+   |
+LL |     let _ = e();
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:41:5
@@ -37,7 +53,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = f();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:41:10
+   |
+LL |     let _ = f();
+   |          ^
 
 error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.rs b/src/tools/clippy/tests/ui/let_with_type_underscore.rs
index 175718b94c8..7c1835e8cd1 100644
--- a/src/tools/clippy/tests/ui/let_with_type_underscore.rs
+++ b/src/tools/clippy/tests/ui/let_with_type_underscore.rs
@@ -12,7 +12,7 @@ fn main() {
     let _: _ = 2;
     let x: _ = func();
 
-    let x = 1; // Will not lint, Rust inferres this to an integer before Clippy
+    let x = 1; // Will not lint, Rust infers this to an integer before Clippy
     let x = func();
     let x: Vec<_> = Vec::<u32>::new();
     let x: [_; 1] = [1];
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index d3cac666763..09fb0d75852 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index 34f0c4d5029..7fee4c95cea 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.fixed b/src/tools/clippy/tests/ui/manual_while_let_some.fixed
new file mode 100644
index 00000000000..8b610919536
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.fixed
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while let Some(number) = numbers.pop() {
+        
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while let Some(number) = val.numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while let Some((a, b)) = numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32_tuple(element);
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while let Some(Foo { a, b }) = results.pop() {
+        
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.rs b/src/tools/clippy/tests/ui/manual_while_let_some.rs
new file mode 100644
index 00000000000..85a0a084a42
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.rs
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while !numbers.is_empty() {
+        let number = numbers.pop().unwrap();
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while !val.numbers.is_empty() {
+        let number = val.numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().expect(""));
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while !numbers.is_empty() {
+        let (a, b) = numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32_tuple(numbers.pop().unwrap());
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while !results.is_empty() {
+        let Foo { a, b } = results.pop().unwrap();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.stderr b/src/tools/clippy/tests/ui/manual_while_let_some.stderr
new file mode 100644
index 00000000000..633fe05c49b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_while_let_some.stderr
@@ -0,0 +1,87 @@
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:23:9
+   |
+LL |         let number = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-while-let-some` implied by `-D warnings`
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:31:9
+   |
+LL |         let number = val.numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = val.numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:35:20
+   |
+LL |         accept_i32(numbers.pop().unwrap());
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:39:20
+   |
+LL |         accept_i32(numbers.pop().expect(""));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:82:9
+   |
+LL |         let (a, b) = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some((a, b)) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:86:26
+   |
+LL |         accept_i32_tuple(numbers.pop().unwrap());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32_tuple(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:91:9
+   |
+LL |         let Foo { a, b } = results.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(Foo { a, b }) = results.pop() {
+LL ~         
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.fixed b/src/tools/clippy/tests/ui/needless_bool_assign.fixed
new file mode 100644
index 00000000000..3ed31d4d711
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.fixed
@@ -0,0 +1,33 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    a.field = random() && random();
+    a.field = !(random() && random());
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    random(); a.field = true;
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.rs b/src/tools/clippy/tests/ui/needless_bool_assign.rs
new file mode 100644
index 00000000000..efaeb67fa45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.rs
@@ -0,0 +1,45 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    if random() && random() {
+        a.field = true;
+    } else {
+        a.field = false
+    }
+    if random() && random() {
+        a.field = false;
+    } else {
+        a.field = true
+    }
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    if random() {
+        a.field = true;
+    } else {
+        a.field = true;
+    }
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr
new file mode 100644
index 00000000000..601bbed5493
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr
@@ -0,0 +1,53 @@
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:15:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = false
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = random() && random();`
+   |
+   = note: `-D clippy::needless-bool-assign` implied by `-D warnings`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:20:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = false;
+LL | |     } else {
+LL | |         a.field = true
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = !(random() && random());`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:34:5
+   |
+LL | /     if random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = true;
+LL | |     }
+   | |_____^ help: you can reduce it to: `random(); a.field = true;`
+
+error: this `if` has identical blocks
+  --> $DIR/needless_bool_assign.rs:34:17
+   |
+LL |       if random() {
+   |  _________________^
+LL | |         a.field = true;
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/needless_bool_assign.rs:36:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         a.field = true;
+LL | |     }
+   | |_____^
+   = note: `#[deny(clippy::if_same_then_else)]` on by default
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
index a04f9ec651e..92572942bc0 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
index 4975c705081..95acbdff8cc 100644
--- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
index b32e721110e..818119f7be5 100644
--- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
@@ -25,7 +25,7 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin
     0
 }
 
-// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"`
 #[no_mangle]
 #[rustfmt::skip]
 extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 9aebcf47100..57f341e0276 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -97,7 +97,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index b40b324902a..19f9f704517 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -120,7 +120,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 87100b97288..d62f7d26a35 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -54,6 +54,8 @@ fn main() {
     } else {
         3
     };
+
+    if gen_opt().is_some() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 0b69e13f655..d6429426573 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -63,6 +63,8 @@ fn main() {
     } else {
         3
     };
+
+    if let Some(..) = gen_opt() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 27ff812ba45..7c5a047e455 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -89,31 +89,37 @@ LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:80:12
+  --> $DIR/redundant_pattern_matching_option.rs:67:12
+   |
+LL |     if let Some(..) = gen_opt() {}
+   |     -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:82:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:82:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:84:15
+  --> $DIR/redundant_pattern_matching_option.rs:86:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:86:15
+  --> $DIR/redundant_pattern_matching_option.rs:88:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:88:5
+  --> $DIR/redundant_pattern_matching_option.rs:90:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -122,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:93:5
+  --> $DIR/redundant_pattern_matching_option.rs:95:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -131,16 +137,16 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:101:12
+  --> $DIR/redundant_pattern_matching_option.rs:103:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:102:12
+  --> $DIR/redundant_pattern_matching_option.rs:104:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index ff19a042825..42a59f6d43d 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 38b1647c0cc..4d173e8cbbf 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 70d15408b9f..0da4ed7520c 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,253 +7,253 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs
index daef95a425c..f31a7e33c4b 100644
--- a/src/tools/clippy/tests/ui/same_name_method.rs
+++ b/src/tools/clippy/tests/ui/same_name_method.rs
@@ -62,7 +62,7 @@ mod should_lint {
         impl T1 for S {}
     }
 
-    mod multiply_conflicit_trait {
+    mod multiple_conflicting_traits {
         use crate::{T1, T2};
 
         struct S;
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 03337ec3564..2c0fc3e3fd8 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -8,6 +8,12 @@ extern crate proc_macro_derive;
 #[derive(proc_macro_derive::ShadowDerive)]
 pub struct Nothing;
 
+macro_rules! reuse {
+    ($v:ident) => {
+        let $v = $v + 1;
+    };
+}
+
 fn shadow_same() {
     let x = 1;
     let x = x;
@@ -33,6 +39,12 @@ fn shadow_reuse() -> Option<()> {
     None
 }
 
+fn shadow_reuse_macro() {
+    let x = 1;
+    // this should not warn
+    reuse!(x);
+}
+
 fn shadow_unrelated() {
     let x = 1;
     let x = 2;
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 92bb937d086..8321f6df224 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:12:9
+  --> $DIR/shadow.rs:18:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:14:13
+  --> $DIR/shadow.rs:20:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:14:9
+  --> $DIR/shadow.rs:20:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:16:9
+  --> $DIR/shadow.rs:22:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:29:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:34:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:38:9
+  --> $DIR/shadow.rs:50:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:37:9
+  --> $DIR/shadow.rs:49:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:43:13
+  --> $DIR/shadow.rs:55:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:42:10
+  --> $DIR/shadow.rs:54:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:49:17
+  --> $DIR/shadow.rs:61:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:53:17
+  --> $DIR/shadow.rs:65:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:54:20
+  --> $DIR/shadow.rs:66:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:56:13
+  --> $DIR/shadow.rs:68:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:59:17
+  --> $DIR/shadow.rs:71:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:58:9
+  --> $DIR/shadow.rs:70:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:95:9
+  --> $DIR/shadow.rs:107:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:94:28
+  --> $DIR/shadow.rs:106:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:101:21
+  --> $DIR/shadow.rs:113:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:100:13
+  --> $DIR/shadow.rs:112:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
index 058f2aa54da..3fc11b8b088 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = b"warning";
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = b"hello there";
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = b"lit to string".to_vec();
     let bs = b"lit to owned".to_vec();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
index b550bea001f..7d54acf630e 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = $b.as_bytes();
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = "hello there".as_bytes();
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = "lit to string".to_string().into_bytes();
     let bs = "lit to owned".to_owned().into_bytes();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
index f47d6161c6c..61b4e210e0f 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
@@ -1,5 +1,5 @@
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:7:14
+  --> $DIR/string_lit_as_bytes.rs:17:14
    |
 LL |     let bs = "hello there".as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
@@ -7,34 +7,45 @@ LL |     let bs = "hello there".as_bytes();
    = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:9:14
+  --> $DIR/string_lit_as_bytes.rs:19:14
    |
 LL |     let bs = r###"raw string with 3# plus " ""###.as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:11:14
+  --> $DIR/string_lit_as_bytes.rs:21:14
    |
 LL |     let bs = "lit to string".to_string().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:12:14
+  --> $DIR/string_lit_as_bytes.rs:22:14
    |
 LL |     let bs = "lit to owned".to_owned().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()`
 
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:12:26
+   |
+LL |         const B: &[u8] = $b.as_bytes();
+   |                          ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"`
+...
+LL |     b!("warning");
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: calling `as_bytes()` on `include_str!(..)`
-  --> $DIR/string_lit_as_bytes.rs:25:22
+  --> $DIR/string_lit_as_bytes.rs:39:22
    |
 LL |     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:27:13
+  --> $DIR/string_lit_as_bytes.rs:41:13
    |
 LL |     let _ = "string with newline/t/n".as_bytes();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"`
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs
index 8e3749eef35..928475b5f35 100644
--- a/src/tools/clippy/tests/ui/trailing_empty_array.rs
+++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs
@@ -144,7 +144,7 @@ struct ReprCAlign {
 
 // NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
 #[repr(C)]
-enum DontLintAnonymousStructsFromDesuraging {
+enum DontLintAnonymousStructsFromDesugaring {
     A(u32),
     B(f32, [u64; 0]),
     C { x: u32, y: [u64; 0] },
diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs
index c996de89422..2d567630e15 100644
--- a/src/tools/clippy/tests/ui/uninit.rs
+++ b/src/tools/clippy/tests/ui/uninit.rs
@@ -17,10 +17,10 @@ fn main() {
     // This is OK, because `MaybeUninit` allows uninitialized data.
     let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
 
     // This is OK, because our own MaybeUninit is just as fine as the one from core.
diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed
index 4623aeeb0eb..20138a29fd1 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.fixed
+++ b/src/tools/clippy/tests/ui/use_self_trait.fixed
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs
index d7d76dd9623..bf697b01a42 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.rs
+++ b/src/tools/clippy/tests/ui/use_self_trait.rs
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
 
     fn vals(_: Bad) -> Bad {
-        Bad::default()
+        Bad
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr
index 090729b9c3d..6257f802dd8 100644
--- a/src/tools/clippy/tests/ui/use_self_trait.stderr
+++ b/src/tools/clippy/tests/ui/use_self_trait.stderr
@@ -63,7 +63,7 @@ LL |     fn vals(_: Bad) -> Bad {
 error: unnecessary structure name repetition
   --> $DIR/use_self_trait.rs:36:9
    |
-LL |         Bad::default()
+LL |         Bad
    |         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index e46ad2c6e0e..8791debad72 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -564,7 +564,7 @@ Otherwise, have a great day =^.^=
     </div>
 
     <a href="https://github.com/rust-lang/rust-clippy">
-        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
+        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"/>
     </a>
 
     <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 81179480ed8..4a57c61406c 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -115,6 +115,11 @@ pub(super) fn handle_needs(
             condition: cache.x86_64_dlltool,
             ignore_reason: "ignored when dlltool for x86_64 is not present",
         },
+        Need {
+            name: "needs-dlltool",
+            condition: cache.dlltool,
+            ignore_reason: "ignored when dlltool for the current architecture is not present",
+        },
         Need {
             name: "needs-git-hash",
             condition: config.git_hash,
@@ -183,6 +188,7 @@ pub(super) struct CachedNeedsConditions {
     rust_lld: bool,
     i686_dlltool: bool,
     x86_64_dlltool: bool,
+    dlltool: bool,
 }
 
 impl CachedNeedsConditions {
@@ -190,6 +196,17 @@ impl CachedNeedsConditions {
         let path = std::env::var_os("PATH").expect("missing PATH environment variable");
         let path = std::env::split_paths(&path).collect::<Vec<_>>();
 
+        // On Windows, dlltool.exe is used for all architectures.
+        #[cfg(windows)]
+        let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file());
+
+        // For non-Windows, there are architecture specific dlltool binaries.
+        #[cfg(not(windows))]
+        let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file());
+        #[cfg(not(windows))]
+        let x86_64_dlltool =
+            path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file());
+
         let target = &&*config.target;
         Self {
             sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
@@ -225,17 +242,26 @@ impl CachedNeedsConditions {
                 .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" })
                 .exists(),
 
-            // On Windows, dlltool.exe is used for all architectures.
             #[cfg(windows)]
-            i686_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            i686_dlltool: dlltool,
             #[cfg(windows)]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()),
+            x86_64_dlltool: dlltool,
+            #[cfg(windows)]
+            dlltool,
 
             // For non-Windows, there are architecture specific dlltool binaries.
             #[cfg(not(windows))]
-            i686_dlltool: path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()),
+            i686_dlltool,
             #[cfg(not(windows))]
-            x86_64_dlltool: path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()),
+            x86_64_dlltool,
+            #[cfg(not(windows))]
+            dlltool: if config.matches_arch("x86") {
+                i686_dlltool
+            } else if config.matches_arch("x86_64") {
+                x86_64_dlltool
+            } else {
+                false
+            },
         }
     }
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a4be7af886b..4ede4603789 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1483,7 +1483,16 @@ impl<'test> TestCx<'test> {
     }
 
     fn compile_test(&self, will_execute: WillExecute, emit: Emit) -> ProcRes {
-        self.compile_test_general(will_execute, emit, self.props.local_pass_mode())
+        self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), Vec::new())
+    }
+
+    fn compile_test_with_passes(
+        &self,
+        will_execute: WillExecute,
+        emit: Emit,
+        passes: Vec<String>,
+    ) -> ProcRes {
+        self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), passes)
     }
 
     fn compile_test_general(
@@ -1491,6 +1500,7 @@ impl<'test> TestCx<'test> {
         will_execute: WillExecute,
         emit: Emit,
         local_pm: Option<PassMode>,
+        passes: Vec<String>,
     ) -> ProcRes {
         // Only use `make_exe_name` when the test ends up being executed.
         let output_file = match will_execute {
@@ -1527,6 +1537,7 @@ impl<'test> TestCx<'test> {
             emit,
             allow_unused,
             LinkToAux::Yes,
+            passes,
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -1777,6 +1788,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::No,
             LinkToAux::No,
+            Vec::new(),
         );
 
         for key in &aux_props.unset_rustc_env {
@@ -1908,6 +1920,7 @@ impl<'test> TestCx<'test> {
         emit: Emit,
         allow_unused: AllowUnused,
         link_to_aux: LinkToAux,
+        passes: Vec<String>, // Vec of passes under mir-opt test to be dumped
     ) -> Command {
         let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
         let is_rustdoc = self.is_rustdoc() && !is_aux;
@@ -2008,9 +2021,18 @@ impl<'test> TestCx<'test> {
                 rustc.arg("-Cstrip=debuginfo");
             }
             MirOpt => {
+                // We check passes under test to minimize the mir-opt test dump
+                // if files_for_miropt_test parses the passes, we dump only those passes
+                // otherwise we conservatively pass -Zdump-mir=all
+                let zdump_arg = if !passes.is_empty() {
+                    format!("-Zdump-mir={}", passes.join(" | "))
+                } else {
+                    "-Zdump-mir=all".to_string()
+                };
+
                 rustc.args(&[
                     "-Copt-level=1",
-                    "-Zdump-mir=all",
+                    &zdump_arg,
                     "-Zvalidate-mir",
                     "-Zdump-mir-exclude-pass-number",
                     "-Zmir-pretty-relative-line-numbers=yes",
@@ -2333,6 +2355,7 @@ impl<'test> TestCx<'test> {
             Emit::LlvmIr,
             AllowUnused::No,
             LinkToAux::Yes,
+            Vec::new(),
         );
 
         self.compose_and_run_compiler(rustc, None)
@@ -2364,8 +2387,14 @@ impl<'test> TestCx<'test> {
             None => self.fatal("missing 'assembly-output' header"),
         }
 
-        let rustc =
-            self.make_compile_args(input_file, output_file, emit, AllowUnused::No, LinkToAux::Yes);
+        let rustc = self.make_compile_args(
+            input_file,
+            output_file,
+            emit,
+            AllowUnused::No,
+            LinkToAux::Yes,
+            Vec::new(),
+        );
 
         (self.compose_and_run_compiler(rustc, None), output_path)
     }
@@ -2496,6 +2525,7 @@ impl<'test> TestCx<'test> {
             Emit::None,
             AllowUnused::Yes,
             LinkToAux::Yes,
+            Vec::new(),
         );
         new_rustdoc.build_all_auxiliary(&mut rustc);
 
@@ -3310,7 +3340,8 @@ impl<'test> TestCx<'test> {
         if let Some(FailMode::Build) = self.props.fail_mode {
             // Make sure a build-fail test cannot fail due to failing analysis (e.g. typeck).
             let pm = Some(PassMode::Check);
-            let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm);
+            let proc_res =
+                self.compile_test_general(WillExecute::No, Emit::Metadata, pm, Vec::new());
             self.check_if_test_should_compile(&proc_res, pm);
         }
 
@@ -3479,6 +3510,7 @@ impl<'test> TestCx<'test> {
                 emit_metadata,
                 AllowUnused::No,
                 LinkToAux::Yes,
+                Vec::new(),
             );
             let res = self.compose_and_run_compiler(rustc, None);
             if !res.status.success() {
@@ -3497,14 +3529,14 @@ impl<'test> TestCx<'test> {
         let pm = self.pass_mode();
         let should_run = self.should_run(pm);
         let emit_metadata = self.should_emit_metadata(pm);
-        let proc_res = self.compile_test(should_run, emit_metadata);
+        let passes = self.get_passes();
 
+        let proc_res = self.compile_test_with_passes(should_run, emit_metadata, passes);
+        self.check_mir_dump();
         if !proc_res.status.success() {
             self.fatal_proc_rec("compilation failed!", &proc_res);
         }
 
-        self.check_mir_dump();
-
         if let WillExecute::Yes = should_run {
             let proc_res = self.exec_compiled_test();
 
@@ -3514,6 +3546,26 @@ impl<'test> TestCx<'test> {
         }
     }
 
+    fn get_passes(&self) -> Vec<String> {
+        let files = miropt_test_tools::files_for_miropt_test(
+            &self.testpaths.file,
+            self.config.get_pointer_width(),
+        );
+
+        let mut out = Vec::new();
+
+        for miropt_test_tools::MiroptTestFiles {
+            from_file: _,
+            to_file: _,
+            expected_file: _,
+            passes,
+        } in files
+        {
+            out.extend(passes);
+        }
+        out
+    }
+
     fn check_mir_dump(&self) {
         let test_file_contents = fs::read_to_string(&self.testpaths.file).unwrap();
 
@@ -3543,8 +3595,9 @@ impl<'test> TestCx<'test> {
             &self.testpaths.file,
             self.config.get_pointer_width(),
         );
-
-        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file } in files {
+        for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file, passes: _ } in
+            files
+        {
             let dumped_string = if let Some(after) = to_file {
                 self.diff_mir_files(from_file.into(), after.into())
             } else {
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index a72b44d003f..e95c955a9a1 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-74c4821045c68d42bb8b8a7c998bdb5c2a72bd0d
+c4190f2d3a46a59f435f7b42f58bc22b2f4d6917
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index a77b6e53353..28f9912e283 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -288,11 +288,10 @@ fn main() {
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
     let env_snapshot = env::vars_os().collect::<Vec<_>>();
 
-    // Earliest rustc setup.
-    rustc_driver::install_ice_hook();
-
     // If the environment asks us to actually be rustc, then do that.
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
+        // Earliest rustc setup.
+        rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
         rustc_driver::init_rustc_env_logger();
 
         let target_crate = if crate_kind == "target" {
@@ -311,6 +310,9 @@ fn main() {
         )
     }
 
+    // Add an ICE bug report hook.
+    rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
+
     // Init loggers the Miri way.
     init_early_loggers();
 
diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs
index cfba7d583b1..f86c3ce0afe 100644
--- a/src/tools/miropt-test-tools/src/lib.rs
+++ b/src/tools/miropt-test-tools/src/lib.rs
@@ -4,6 +4,8 @@ pub struct MiroptTestFiles {
     pub expected_file: std::path::PathBuf,
     pub from_file: String,
     pub to_file: Option<String>,
+    /// Vec of passes under test to be dumped
+    pub passes: Vec<String>,
 }
 
 pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<MiroptTestFiles> {
@@ -28,9 +30,11 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
             let mut expected_file;
             let from_file;
             let to_file;
+            let mut passes = Vec::new();
 
             if test_name.ends_with(".diff") {
                 let trimmed = test_name.trim_end_matches(".diff");
+                passes.push(trimmed.split('.').last().unwrap().to_owned());
                 let test_against = format!("{}.after.mir", trimmed);
                 from_file = format!("{}.before.mir", trimmed);
                 expected_file = format!("{}{}.diff", trimmed, bit_width);
@@ -38,7 +42,14 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                 to_file = Some(test_against);
             } else if let Some(first_pass) = test_names.next() {
                 let second_pass = test_names.next().unwrap();
+                if let Some((first_pass_name, _)) = first_pass.split_once('.') {
+                    passes.push(first_pass_name.to_owned());
+                }
+                if let Some((second_pass_name, _)) = second_pass.split_once('.') {
+                    passes.push(second_pass_name.to_owned());
+                }
                 assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
+
                 expected_file =
                     format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass);
                 let second_file = format!("{}.{}.mir", test_name, second_pass);
@@ -51,18 +62,24 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<
                     .next()
                     .expect("test_name has an invalid extension");
                 let extension = cap.get(1).unwrap().as_str();
+
                 expected_file =
                     format!("{}{}{}", test_name.trim_end_matches(extension), bit_width, extension,);
                 from_file = test_name.to_string();
                 assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
                 to_file = None;
+                // the pass name is the third to last string in the test name
+                // this gets pushed into passes
+                passes.push(
+                    test_name.split('.').rev().nth(2).expect("invalid test format").to_string(),
+                );
             };
             if !expected_file.starts_with(&test_crate) {
                 expected_file = format!("{}.{}", test_crate, expected_file);
             }
             let expected_file = test_dir.join(expected_file);
 
-            out.push(MiroptTestFiles { expected_file, from_file, to_file });
+            out.push(MiroptTestFiles { expected_file, from_file, to_file, passes });
         }
     }
 
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index be64559e877..47846424b06 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -1,3 +1,5 @@
+#![feature(rustc_private)]
+
 use anyhow::{format_err, Result};
 
 use io::Error as IoError;
@@ -19,7 +21,14 @@ use crate::rustfmt::{
     FormatReportFormatterBuilder, Input, Session, Verbosity,
 };
 
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rustfmt/issues/new?labels=bug";
+
+// N.B. these crates are loaded from the sysroot, so they need extern crate.
+extern crate rustc_driver;
+
 fn main() {
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ());
+
     env_logger::Builder::from_env("RUSTFMT_LOG").init();
     let opts = make_opts();
 
diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs
index d8166ead8c4..a84e78254f2 100644
--- a/src/tools/suggest-tests/src/static_suggestions.rs
+++ b/src/tools/suggest-tests/src/static_suggestions.rs
@@ -15,7 +15,7 @@ static_suggestions! {
 
     "compiler/*" => [
         sug!("check"),
-        sug!("test", 1, ["src/test/ui", "src/test/run-make"])
+        sug!("test", 1, ["tests/ui", "tests/run-make"])
     ],
 
     "src/librustdoc/*" => [
diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs
index 5bc1a7df7ca..b4149136fa3 100644
--- a/src/tools/suggest-tests/src/tests.rs
+++ b/src/tools/suggest-tests/src/tests.rs
@@ -12,7 +12,7 @@ macro_rules! sugg_test {
 
 sugg_test! {
     test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] =>
-        ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test src/test/ui src/test/run-make 1"],
+        ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"],
 
     test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"],
 
diff --git a/tests/assembly/slice-is_ascii.rs b/tests/assembly/slice-is_ascii.rs
new file mode 100644
index 00000000000..b3e1fee15a7
--- /dev/null
+++ b/tests/assembly/slice-is_ascii.rs
@@ -0,0 +1,35 @@
+// revisions: WIN LIN
+// [WIN] only-windows
+// [LIN] only-linux
+// assembly-output: emit-asm
+// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
+// min-llvm-version: 14
+// only-x86_64
+// ignore-sgx
+// ignore-debug
+
+#![feature(str_internals)]
+
+// CHECK-LABEL: is_ascii_simple_demo:
+#[no_mangle]
+pub fn is_ascii_simple_demo(bytes: &[u8]) -> bool {
+    // Linux (System V): pointer is rdi; length is rsi
+    // Windows: pointer is rcx; length is rdx.
+
+    // CHECK-NOT: mov
+    // CHECK-NOT: test
+    // CHECK-NOT: cmp
+
+    // CHECK: .[[LOOPHEAD:.+]]:
+    // CHECK-NEXT: mov [[TEMP:.+]], [[LEN:rsi|rdx]]
+    // CHECK-NEXT: sub [[LEN]], 1
+    // CHECK-NEXT: jb .[[LOOPEXIT:.+]]
+    // CHECK-NEXT: cmp byte ptr [{{rdi|rcx}} + [[TEMP]] - 1], 0
+    // CHECK-NEXT: jns .[[LOOPHEAD]]
+
+    // CHECK-NEXT: .[[LOOPEXIT]]:
+    // CHECK-NEXT: test [[TEMP]], [[TEMP]]
+    // CHECK-NEXT: sete al
+    // CHECK-NEXT: ret
+    core::slice::is_ascii_simple(bytes)
+}
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
index 9b69f79c28e..169e99deee7 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir
@@ -21,42 +21,42 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc18─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc19─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc18 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc5──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc19 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc6──╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc5 (size: 0, align: 4) {}
+alloc6 (size: 0, align: 4) {}
 
-alloc8 (size: 16, align: 4) {
-    ╾─alloc9──╼ 03 00 00 00 ╾─alloc10─╼ 03 00 00 00 │ ╾──╼....╾──╼....
-}
-
-alloc9 (size: 3, align: 1) {
-    66 6f 6f                                        │ foo
+alloc9 (size: 16, align: 4) {
+    ╾─alloc10─╼ 03 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ╾──╼....╾──╼....
 }
 
 alloc10 (size: 3, align: 1) {
+    66 6f 6f                                        │ foo
+}
+
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 24, align: 4) {
-    0x00 │ ╾─alloc14─╼ 03 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ╾──╼....╾──╼....
-    0x10 │ ╾─alloc16─╼ 04 00 00 00                         │ ╾──╼....
-}
-
-alloc14 (size: 3, align: 1) {
-    6d 65 68                                        │ meh
+alloc14 (size: 24, align: 4) {
+    0x00 │ ╾─alloc15─╼ 03 00 00 00 ╾─alloc16─╼ 03 00 00 00 │ ╾──╼....╾──╼....
+    0x10 │ ╾─alloc17─╼ 04 00 00 00                         │ ╾──╼....
 }
 
 alloc15 (size: 3, align: 1) {
+    6d 65 68                                        │ meh
+}
+
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
index d0f196e7245..db1f9648843 100644
--- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir
@@ -21,46 +21,46 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc18───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc19───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc18 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc5────────╼ │ ....░░░░╾──────╼
+alloc19 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc6────────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc9────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc14───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc5 (size: 0, align: 8) {}
+alloc6 (size: 0, align: 8) {}
 
-alloc8 (size: 32, align: 8) {
-    0x00 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-}
-
-alloc9 (size: 3, align: 1) {
-    66 6f 6f                                        │ foo
+alloc9 (size: 32, align: 8) {
+    0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc11───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc10 (size: 3, align: 1) {
+    66 6f 6f                                        │ foo
+}
+
+alloc11 (size: 3, align: 1) {
     62 61 72                                        │ bar
 }
 
-alloc13 (size: 48, align: 8) {
-    0x00 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x10 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x20 │ ╾───────alloc16───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
-}
-
-alloc14 (size: 3, align: 1) {
-    6d 65 68                                        │ meh
+alloc14 (size: 48, align: 8) {
+    0x00 │ ╾───────alloc15───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x10 │ ╾───────alloc16───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x20 │ ╾───────alloc17───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
 alloc15 (size: 3, align: 1) {
+    6d 65 68                                        │ meh
+}
+
+alloc16 (size: 3, align: 1) {
     6d 6f 70                                        │ mop
 }
 
-alloc16 (size: 4, align: 1) {
+alloc17 (size: 4, align: 1) {
     6d c3 b6 70                                     │ m..p
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
index aab005c52d6..999acb48afe 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir
@@ -21,41 +21,41 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 4) {
-    ╾─alloc22─╼ 03 00 00 00                         │ ╾──╼....
+    ╾─alloc23─╼ 03 00 00 00                         │ ╾──╼....
 }
 
-alloc22 (size: 48, align: 4) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc9──╼ 00 00 00 00 │ ....░░░░╾──╼....
-    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼....
-    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc20─╼ 03 00 00 00 │ ....*...╾──╼....
+alloc23 (size: 48, align: 4) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc10─╼ 00 00 00 00 │ ....░░░░╾──╼....
+    0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc15─╼ 02 00 00 00 │ ....░░░░╾──╼....
+    0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼....
 }
 
-alloc9 (size: 0, align: 4) {}
+alloc10 (size: 0, align: 4) {}
 
-alloc14 (size: 8, align: 4) {
-    ╾─alloc12─╼ ╾─alloc13─╼                         │ ╾──╼╾──╼
-}
-
-alloc12 (size: 1, align: 1) {
-    05                                              │ .
+alloc15 (size: 8, align: 4) {
+    ╾─alloc13─╼ ╾─alloc14─╼                         │ ╾──╼╾──╼
 }
 
 alloc13 (size: 1, align: 1) {
+    05                                              │ .
+}
+
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 12, align: 4) {
-    ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a19+0x2─╼             │ ╾──╼╾──╼╾──╼
+alloc21 (size: 12, align: 4) {
+    ╾─a18+0x3─╼ ╾─alloc19─╼ ╾─a20+0x2─╼             │ ╾──╼╾──╼╾──╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
index 0eff9474c20..30311890eee 100644
--- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
@@ -21,44 +21,44 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 16, align: 8) {
-    ╾───────alloc22───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
+    ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
 }
 
-alloc22 (size: 72, align: 8) {
-    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc9────────╼ │ ....░░░░╾──────╼
+alloc23 (size: 72, align: 8) {
+    0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc10───────╼ │ ....░░░░╾──────╼
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
-    0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
-    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc20───────╼ │ ....*...╾──────╼
+    0x20 │ ╾───────alloc15───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
+    0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼
     0x40 │ 03 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc9 (size: 0, align: 8) {}
+alloc10 (size: 0, align: 8) {}
 
-alloc14 (size: 16, align: 8) {
-    ╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼
-}
-
-alloc12 (size: 1, align: 1) {
-    05                                              │ .
+alloc15 (size: 16, align: 8) {
+    ╾───────alloc13───────╼ ╾───────alloc14───────╼ │ ╾──────╼╾──────╼
 }
 
 alloc13 (size: 1, align: 1) {
+    05                                              │ .
+}
+
+alloc14 (size: 1, align: 1) {
     06                                              │ .
 }
 
-alloc20 (size: 24, align: 8) {
-    0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼
-    0x10 │ ╾─────alloc19+0x2─────╼                         │ ╾──────╼
+alloc21 (size: 24, align: 8) {
+    0x00 │ ╾─────alloc18+0x3─────╼ ╾───────alloc19───────╼ │ ╾──────╼╾──────╼
+    0x10 │ ╾─────alloc20+0x2─────╼                         │ ╾──────╼
 }
 
-alloc17 (size: 4, align: 1) {
+alloc18 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
 
-alloc18 (size: 1, align: 1) {
+alloc19 (size: 1, align: 1) {
     2a                                              │ *
 }
 
-alloc19 (size: 4, align: 1) {
+alloc20 (size: 4, align: 1) {
     2a 45 15 6f                                     │ *E.o
 }
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
index 55c6db5d0ce..d592e59fafd 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir
@@ -21,30 +21,30 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 4, align: 4) {
-    ╾─alloc11─╼                                     │ ╾──╼
+    ╾─alloc12─╼                                     │ ╾──╼
 }
 
-alloc11 (size: 168, align: 1) {
+alloc12 (size: 168, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc6──╼ │ ............╾──╼
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc7──╼ │ ............╾──╼
     0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
-    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc8──╼ 00 00 │ ..........╾──╼..
-    0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
+    0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc9──╼ 00 00 │ ..........╾──╼..
+    0x90 │ ╾a10+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
     0xa0 │ 00 00 00 00 00 00 00 00                         │ ........
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
index 27492a7fd22..ca53b28be7c 100644
--- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
+++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir
@@ -21,12 +21,12 @@ fn main() -> () {
 }
 
 alloc1 (static: FOO, size: 8, align: 8) {
-    ╾───────alloc11───────╼                         │ ╾──────╼
+    ╾───────alloc12───────╼                         │ ╾──────╼
 }
 
-alloc11 (size: 180, align: 1) {
+alloc12 (size: 180, align: 1) {
     0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
-    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc6── │ ............╾───
+    0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc7── │ ............╾───
     0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
     0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
@@ -34,18 +34,18 @@ alloc11 (size: 180, align: 1) {
     0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
-    0x90 │ ─────alloc8─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼
+    0x90 │ ─────alloc9─────╼ 00 00 ╾────alloc10+0x63─────╼ │ ─────╼..╾──────╼
     0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0xb0 │ 00 00 00 00                                     │ ....
 }
 
-alloc6 (size: 4, align: 4) {
+alloc7 (size: 4, align: 4) {
     2a 00 00 00                                     │ *...
 }
 
-alloc8 (fn: main)
+alloc9 (fn: main)
 
-alloc9 (size: 100, align: 1) {
+alloc10 (size: 100, align: 1) {
     0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
     0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
index bedfa5992ad..85d6b5e3d00 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff
@@ -18,29 +18,35 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:9: +1:10
           _1 = const 0_i32;                // scope 0 at $DIR/bad_op_mod_by_zero.rs:+1:13: +1:14
           StorageLive(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:9: +2:11
--         _4 = Eq(_1, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          StorageLive(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+-         _3 = _1;                         // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+-         _4 = Eq(_3, const 0_i32);        // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         _3 = const 0_i32;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
 +         _4 = const true;                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb1: {
--         _5 = Eq(_1, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         _5 = Eq(_3, const -1_i32);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 -         _7 = BitAnd(move _5, move _6);   // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
--         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _1) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _5 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _6 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
 +         _7 = const false;                // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
       }
   
       bb2: {
--         _2 = Rem(const 1_i32, _1);       // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
-+         _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          _2 = Rem(const 1_i32, move _3);  // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:14: +2:19
+          StorageDead(_3);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+2:18: +2:19
+          _0 = const ();                   // scope 0 at $DIR/bad_op_mod_by_zero.rs:+0:11: +3:2
           StorageDead(_2);                 // scope 1 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
+          StorageDead(_1);                 // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/bad_op_mod_by_zero.rs:+3:2: +3:2
       }
   }
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
index a1078472cbf..93d558250ea 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR bad_op_mod_by_zero.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
index e711babf035..f63ee705d92 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
@@ -6,16 +6,17 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
@@ -23,27 +24,31 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
-                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:9:25: 9:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = &(*_9);                     // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _7 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _7 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
index e711babf035..f63ee705d92 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
@@ -6,16 +6,17 @@
       let _1: *const [i32];                // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
       let mut _2: *const [i32; 3];         // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       let _3: &[i32; 3];                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-      let _5: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-      let mut _6: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _7: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-      let mut _8: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+      let _4: [i32; 3];                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:26: +1:35
+      let _6: usize;                       // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+      let mut _7: usize;                   // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _8: bool;                    // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+      let mut _9: &[i32; 3];               // in scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
       scope 1 {
           debug a => _1;                   // in scope 1 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           scope 2 {
-              let _4: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+              let _5: i32;                 // in scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               scope 3 {
-                  debug _b => _4;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+                  debug _b => _5;          // in scope 3 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
               }
           }
       }
@@ -23,27 +24,31 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:9: +1:10
           StorageLive(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
-          _8 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          StorageLive(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _9 = const _;                    // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
                                            // mir::Constant
-                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:6:25: 6:35
+                                           // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:9:25: 9:35
                                            // + literal: Const { ty: &[i32; 3], val: Unevaluated(main, [], Some(promoted[0])) }
-          _2 = &raw const (*_8);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _3 = &(*_9);                     // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
+          _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:25: +1:35
           StorageDead(_2);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:34: +1:35
-          StorageLive(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
-          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _5 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
-          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         _7 = Lt(_5, _6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         _7 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_3);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+1:35: +1:36
+          StorageLive(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15
+          StorageLive(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _6 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24
+          _7 = const 3_usize;              // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
       }
   
       bb1: {
-          _4 = (*_1)[_5];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
-          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
-          StorageDead(_4);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
+          _5 = (*_1)[_6];                  // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25
+          StorageDead(_6);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:25: +3:26
+          _0 = const ();                   // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+2:5: +4:6
+          StorageDead(_5);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+4:5: +4:6
           StorageDead(_1);                 // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:+5:2: +5:2
       }
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
index 3d252f2d221..ef148d16dc2 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.rs
@@ -1,4 +1,7 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
+
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 // EMIT_MIR bad_op_unsafe_oob_for_slices.main.ConstProp.diff
 #[allow(unconditional_panic)]
diff --git a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index 85dedf68ce9..1752d222fe7 100644
--- a/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -7,13 +7,17 @@
       let mut _2: main::InvalidChar;       // in scope 0 at $DIR/invalid_constant.rs:+6:34: +6:63
       let mut _4: E;                       // in scope 0 at $DIR/invalid_constant.rs:+13:25: +13:59
       let mut _5: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:+13:34: +13:55
+      let mut _7: Empty;                   // in scope 0 at $DIR/invalid_constant.rs:+20:35: +20:73
+      let mut _8: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:+20:44: +20:65
       scope 1 {
           debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:+6:9: +6:22
           let _3: [E; 1];                  // in scope 1 at $DIR/invalid_constant.rs:+13:9: +13:21
           scope 3 {
               debug _invalid_tag => _3;    // in scope 3 at $DIR/invalid_constant.rs:+13:9: +13:21
+              let _6: [Empty; 1];          // in scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
               scope 5 {
                   debug _enum_without_variants => const [ZeroSized: Empty]; // in scope 5 at $DIR/invalid_constant.rs:+20:9: +20:31
+                  let _9: main::Str<"���">; // in scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
                   scope 7 {
                       debug _non_utf8_str => const Str::<"���">; // in scope 7 at $DIR/invalid_constant.rs:+24:9: +24:22
                   }
@@ -39,17 +43,25 @@
           StorageLive(_5);                 // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
           _5 = InvalidTag { int: const 4_u32 }; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:55
 -         _4 = (_5.1: E);                  // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
--         _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
 +         _4 = const Scalar(0x00000004): E; // scope 4 at $DIR/invalid_constant.rs:+13:34: +13:57
 +                                          // mir::Constant
 +                                          // + span: no-location
 +                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
-+         _3 = [const Scalar(0x00000004): E]; // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
-+                                          // mir::Constant
-+                                          // + span: no-location
-+                                          // + literal: Const { ty: E, val: Value(Scalar(0x00000004)) }
+          _3 = [move _4];                  // scope 1 at $DIR/invalid_constant.rs:+13:24: +13:60
           StorageDead(_4);                 // scope 1 at $DIR/invalid_constant.rs:+13:59: +13:60
           StorageDead(_5);                 // scope 1 at $DIR/invalid_constant.rs:+13:60: +13:61
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:9: +20:31
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:35: +20:73
+          StorageLive(_8);                 // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+          _8 = NoVariants { int: const 0_u32 }; // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:65
+          nop;                             // scope 6 at $DIR/invalid_constant.rs:+20:44: +20:71
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:34: +20:74
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+20:73: +20:74
+          StorageDead(_8);                 // scope 3 at $DIR/invalid_constant.rs:+20:74: +20:75
+          nop;                             // scope 5 at $DIR/invalid_constant.rs:+24:9: +24:22
+          nop;                             // scope 0 at $DIR/invalid_constant.rs:+0:11: +27:2
+          nop;                             // scope 5 at $DIR/invalid_constant.rs:+27:1: +27:2
+          nop;                             // scope 3 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:+27:1: +27:2
           StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:+27:1: +27:2
           return;                          // scope 0 at $DIR/invalid_constant.rs:+27:2: +27:2
diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs
index eb6172cdff9..bdbc5a1990e 100644
--- a/tests/mir-opt/const_prop/invalid_constant.rs
+++ b/tests/mir-opt/const_prop/invalid_constant.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+RemoveZsts
 // Verify that we can pretty print invalid constants.
 
 #![feature(adt_const_params)]
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
index 5331e5b8212..36336d967a9 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff
@@ -18,17 +18,19 @@
           _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29
           StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
-          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
+-         _4 = Len(_2);                    // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
       }
   
       bb1: {
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
index 5331e5b8212..36336d967a9 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff
@@ -18,17 +18,19 @@
           _2 = [const 0_u8; 5000];         // scope 0 at $DIR/large_array_index.rs:+2:17: +2:29
           StorageLive(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
           _3 = const 2_usize;              // scope 0 at $DIR/large_array_index.rs:+2:30: +2:31
-          _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
+-         _4 = Len(_2);                    // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         _5 = Lt(_3, _4);                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 -         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         _4 = const 5000_usize;           // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
 +         _5 = const true;                 // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
       }
   
       bb1: {
           _1 = _2[_3];                     // scope 0 at $DIR/large_array_index.rs:+2:17: +2:32
           StorageDead(_3);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
           StorageDead(_2);                 // scope 0 at $DIR/large_array_index.rs:+2:32: +2:33
+          _0 = const ();                   // scope 0 at $DIR/large_array_index.rs:+0:11: +3:2
           StorageDead(_1);                 // scope 0 at $DIR/large_array_index.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/large_array_index.rs:+3:2: +3:2
       }
diff --git a/tests/mir-opt/const_prop/large_array_index.rs b/tests/mir-opt/const_prop/large_array_index.rs
index 073f9849568..0876445bf2c 100644
--- a/tests/mir-opt/const_prop/large_array_index.rs
+++ b/tests/mir-opt/const_prop/large_array_index.rs
@@ -1,4 +1,6 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 // EMIT_MIR large_array_index.main.ConstProp.diff
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
index 15c93f270d7..077b9bf8304 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
@@ -3,21 +3,26 @@
   
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +0:11
-      let mut _1: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-      let mut _2: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+      let mut _1: *const fn();             // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+      let mut _2: usize;                   // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+      let mut _3: fn();                    // in scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
       scope 1 {
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
-          _2 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          StorageLive(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+          StorageLive(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageLive(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
+          _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:17
                                            // mir::Constant
-                                           // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
+                                           // + span: $DIR/reify_fn_ptr.rs:5:13: 5:17
                                            // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
-          _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
-          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
-          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:26
+          StorageDead(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:25: +1:26
+          _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:+1:13: +1:41
+          StorageDead(_2);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:40: +1:41
+          StorageDead(_1);                 // scope 0 at $DIR/reify_fn_ptr.rs:+1:41: +1:42
+          _0 = const ();                   // scope 0 at $DIR/reify_fn_ptr.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/reify_fn_ptr.rs:+2:2: +2:2
       }
   }
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index bfe2563ad8a..5f63820669b 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // EMIT_MIR reify_fn_ptr.main.ConstProp.diff
 
 fn main() {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
index 636032adb81..6641220db69 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:+1:18: +1:25
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:+1:26: +1:27
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:+1:26: +1:27
-          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
+-         _5 = Len(_3);                    // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
       }
   
       bb1: {
@@ -35,6 +36,7 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
+          _0 = const ();                   // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
index 636032adb81..6641220db69 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff
@@ -20,11 +20,12 @@
           _3 = [const 42_u32; 8];          // scope 0 at $DIR/repeat.rs:+1:18: +1:25
           StorageLive(_4);                 // scope 0 at $DIR/repeat.rs:+1:26: +1:27
           _4 = const 2_usize;              // scope 0 at $DIR/repeat.rs:+1:26: +1:27
-          _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
+-         _5 = Len(_3);                    // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         _6 = Lt(_4, _5);                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 -         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         _5 = const 8_usize;              // scope 0 at $DIR/repeat.rs:+1:18: +1:28
 +         _6 = const true;                 // scope 0 at $DIR/repeat.rs:+1:18: +1:28
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:+1:18: +1:28
       }
   
       bb1: {
@@ -35,6 +36,7 @@
           StorageDead(_2);                 // scope 0 at $DIR/repeat.rs:+1:31: +1:32
           StorageDead(_4);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
           StorageDead(_3);                 // scope 0 at $DIR/repeat.rs:+1:32: +1:33
+          _0 = const ();                   // scope 0 at $DIR/repeat.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/repeat.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/repeat.rs:+2:2: +2:2
       }
diff --git a/tests/mir-opt/const_prop/repeat.rs b/tests/mir-opt/const_prop/repeat.rs
index 2f3b7d2c502..9c11dbc5b66 100644
--- a/tests/mir-opt/const_prop/repeat.rs
+++ b/tests/mir-opt/const_prop/repeat.rs
@@ -1,7 +1,8 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
-// compile-flags: -O
-
+// compile-flags: -Zmir-enable-passes=+NormalizeArrayLen
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
+
 // EMIT_MIR repeat.main.ConstProp.diff
 fn main() {
     let x: u32 = [42; 8][2] + 0;
diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
index ececd994283..b12d84fa479 100644
--- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
+++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.mir
@@ -2,8 +2,14 @@
 
 fn add() -> u32 {
     let mut _0: u32;                     // return place in scope 0 at $DIR/return_place.rs:+0:13: +0:16
+    let mut _1: (u32, bool);             // in scope 0 at $DIR/return_place.rs:+1:5: +1:10
 
     bb0: {
+        _1 = const (4_u32, false);       // scope 0 at $DIR/return_place.rs:+1:5: +1:10
+        assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:+1:5: +1:10
+    }
+
+    bb1: {
         _0 = const 4_u32;                // scope 0 at $DIR/return_place.rs:+1:5: +1:10
         return;                          // scope 0 at $DIR/return_place.rs:+2:2: +2:2
     }
diff --git a/tests/mir-opt/const_prop/return_place.rs b/tests/mir-opt/const_prop/return_place.rs
index ae119df8518..0e68309f036 100644
--- a/tests/mir-opt/const_prop/return_place.rs
+++ b/tests/mir-opt/const_prop/return_place.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // compile-flags: -C overflow-checks=on
 
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
index a091b4ace20..c2f97a0f622 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
@@ -11,15 +11,23 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+1:9: +1:10
           _1 = const 1_u32;                // scope 0 at $DIR/scalar_literal_propagation.rs:+1:13: +1:14
--         _2 = consume(_1) -> bb1;         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
-+         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+          StorageLive(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
+          StorageLive(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+-         _3 = _1;                         // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
++         _3 = const 1_u32;                // scope 1 at $DIR/scalar_literal_propagation.rs:+2:13: +2:14
+          _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/scalar_literal_propagation.rs:+2:5: +2:15
                                            // mir::Constant
-                                           // + span: $DIR/scalar_literal_propagation.rs:5:5: 5:12
+                                           // + span: $DIR/scalar_literal_propagation.rs:6:5: 6:12
                                            // + literal: Const { ty: fn(u32) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:14: +2:15
+          StorageDead(_2);                 // scope 1 at $DIR/scalar_literal_propagation.rs:+2:15: +2:16
+          _0 = const ();                   // scope 0 at $DIR/scalar_literal_propagation.rs:+0:11: +3:2
+          StorageDead(_1);                 // scope 0 at $DIR/scalar_literal_propagation.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/scalar_literal_propagation.rs:+3:2: +3:2
       }
   }
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.rs b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
index e13e352f8a1..fc33cc2d021 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR scalar_literal_propagation.main.ConstProp.diff
 fn main() {
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
index 85704c48a2c..664b7839ffc 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.ConstProp.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:10:14: 10:17
+                                           // + span: $DIR/switch_int.rs:12:14: 12:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:11:14: 11:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index 0864db22523..ef2c4d5faa6 100644
--- a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -15,14 +15,14 @@
       bb1: {
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:+3:14: +3:21
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:10:14: 10:17
+                                           // + span: $DIR/switch_int.rs:12:14: 12:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:+2:14: +2:20
                                            // mir::Constant
-                                           // + span: $DIR/switch_int.rs:9:14: 9:17
+                                           // + span: $DIR/switch_int.rs:11:14: 11:17
                                            // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
diff --git a/tests/mir-opt/const_prop/switch_int.rs b/tests/mir-opt/const_prop/switch_int.rs
index 2a2322e43a9..7158ea4d2bd 100644
--- a/tests/mir-opt/const_prop/switch_int.rs
+++ b/tests/mir-opt/const_prop/switch_int.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstProp
+// compile-flags: -Zmir-enable-passes=+SimplifyConstCondition-after-const-prop
 // ignore-wasm32 compiled with panic=abort by default
 #[inline(never)]
 fn foo(_: i32) { }
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 12313b6c58d..e4a7c0d1e72 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -11,15 +11,24 @@
       }
   
       bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+1:9: +1:10
 -         _1 = (const 1_u32, const 2_u32); // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
 +         _1 = const (1_u32, 2_u32);       // scope 0 at $DIR/tuple_literal_propagation.rs:+1:13: +1:19
-          _2 = consume(_1) -> bb1;         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
+          StorageLive(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
+          StorageLive(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
+-         _3 = _1;                         // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
++         _3 = const (1_u32, 2_u32);       // scope 1 at $DIR/tuple_literal_propagation.rs:+3:13: +3:14
+          _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/tuple_literal_propagation.rs:+3:5: +3:15
                                            // mir::Constant
-                                           // + span: $DIR/tuple_literal_propagation.rs:6:5: 6:12
+                                           // + span: $DIR/tuple_literal_propagation.rs:7:5: 7:12
                                            // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
+          StorageDead(_3);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:14: +3:15
+          StorageDead(_2);                 // scope 1 at $DIR/tuple_literal_propagation.rs:+3:15: +3:16
+          _0 = const ();                   // scope 0 at $DIR/tuple_literal_propagation.rs:+0:11: +4:2
+          StorageDead(_1);                 // scope 0 at $DIR/tuple_literal_propagation.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/tuple_literal_propagation.rs:+4:2: +4:2
       }
   }
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
index edd748d00ab..f342ae2700e 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs
@@ -1,3 +1,4 @@
+// unit-test: ConstProp
 // ignore-wasm32 compiled with panic=abort by default
 // EMIT_MIR tuple_literal_propagation.main.ConstProp.diff
 fn main() {
diff --git a/tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
similarity index 54%
rename from tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
rename to tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
index a4f2d8c84d8..37732421870 100644
--- a/tests/mir-opt/while_let_loops.change_loop_body.ConstProp.diff
+++ b/tests/mir-opt/const_prop/while_let_loops.change_loop_body.ConstProp.diff
@@ -4,8 +4,13 @@
   fn change_loop_body() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
       let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-      let mut _2: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
-      let mut _3: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+      let mut _2: ();                      // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2
+      let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32
+      let mut _4: isize;                   // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25
+      let mut _5: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6
+      let mut _6: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let _7: ();                          // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
+      let mut _8: !;                       // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
           scope 2 {
@@ -15,29 +20,33 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
           _1 = const 0_i32;                // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19
-          StorageLive(_2);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
-          _2 = Option::<u32>::None;        // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
--         _3 = discriminant(_2);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
--         switchInt(move _3) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
-+         _3 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          StorageLive(_3);                 // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+          _3 = Option::<u32>::None;        // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32
+-         _4 = discriminant(_3);           // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+-         switchInt(move _4) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
++         _4 = const 0_isize;              // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
 +         switchInt(const 0_isize) -> [1: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb1: {
-          switchInt(((_2 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
+          switchInt(((_3 as Some).0: u32)) -> [0: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25
       }
   
       bb2: {
           _1 = const 1_i32;                // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15
+          _0 = const ();                   // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
           goto -> bb4;                     // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14
       }
   
       bb3: {
+          StorageLive(_7);                 // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          _0 = const ();                   // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6
+          StorageDead(_7);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           goto -> bb4;                     // scope 1 at no-location
       }
   
       bb4: {
-          StorageDead(_2);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
+          StorageDead(_3);                 // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6
           StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
           return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
       }
diff --git a/tests/mir-opt/while_let_loops.rs b/tests/mir-opt/const_prop/while_let_loops.rs
similarity index 77%
rename from tests/mir-opt/while_let_loops.rs
rename to tests/mir-opt/const_prop/while_let_loops.rs
index fc56cd6985d..595a94b88be 100644
--- a/tests/mir-opt/while_let_loops.rs
+++ b/tests/mir-opt/const_prop/while_let_loops.rs
@@ -1,5 +1,5 @@
+// unit-test: ConstProp
 // EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff
-// EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir
 
 pub fn change_loop_body() {
     let mut _x = 0;
diff --git a/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir b/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
deleted file mode 100644
index 15b0aece8f5..00000000000
--- a/tests/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir
+++ /dev/null
@@ -1,17 +0,0 @@
-// MIR for `change_loop_body` after PreCodegen
-
-fn change_loop_body() -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27
-    let mut _1: i32;                     // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-    scope 1 {
-        debug _x => _1;                  // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15
-        scope 2 {
-        }
-    }
-
-    bb0: {
-        StorageLive(_1);                 // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15
-        StorageDead(_1);                 // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2
-        return;                          // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2
-    }
-}
diff --git a/tests/run-make/issue-109934-lto-debuginfo/Makefile b/tests/run-make/issue-109934-lto-debuginfo/Makefile
new file mode 100644
index 00000000000..3b7a99d3dbc
--- /dev/null
+++ b/tests/run-make/issue-109934-lto-debuginfo/Makefile
@@ -0,0 +1,12 @@
+# ignore-cross-compile
+include ../tools.mk
+
+# With the upgrade to LLVM 16, this was getting:
+#
+#   error: Cannot represent a difference across sections
+#
+# The error stemmed from DI function definitions under type scopes, fixed by
+# only declaring in type scope and defining the subprogram elsewhere.
+
+all:
+	$(RUSTC) lib.rs --test -C lto=fat -C debuginfo=2 -C incremental=$(TMPDIR)/inc-fat
diff --git a/tests/run-make/issue-109934-lto-debuginfo/lib.rs b/tests/run-make/issue-109934-lto-debuginfo/lib.rs
new file mode 100644
index 00000000000..c405928bd18
--- /dev/null
+++ b/tests/run-make/issue-109934-lto-debuginfo/lib.rs
@@ -0,0 +1,9 @@
+extern crate alloc;
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn something_alloc() {
+        assert_eq!(Vec::<u32>::new(), Vec::<u32>::new());
+    }
+}
diff --git a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
index 22f222c12c3..dcb5fee9ecc 100644
--- a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -1,5 +1,4 @@
 #![feature(abi_vectorcall)]
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 
 #[repr(C)]
 #[derive(Clone)]
diff --git a/tests/run-make/raw-dylib-c/lib.rs b/tests/run-make/raw-dylib-c/lib.rs
index 5fb1204037c..f17125f308c 100644
--- a/tests/run-make/raw-dylib-c/lib.rs
+++ b/tests/run-make/raw-dylib-c/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs
index 51bf2ec6b6e..3338ac0a0b5 100644
--- a/tests/run-make/raw-dylib-cross-compilation/lib.rs
+++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(no_core, lang_items)]
 #![no_std]
 #![no_core]
diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile
new file mode 100644
index 00000000000..f5d5360a3fb
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/Makefile
@@ -0,0 +1,11 @@
+# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary.
+
+# only-windows
+# only-gnu
+# needs-dlltool
+
+include ../tools.mk
+
+all:
+	$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd
+	$(DIFF) output.txt "$(TMPDIR)"/output.txt
diff --git a/tests/run-make/raw-dylib-custom-dlltool/lib.rs b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
new file mode 100644
index 00000000000..2f3f497a00d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/lib.rs
@@ -0,0 +1,10 @@
+#[link(name = "extern_1", kind = "raw-dylib")]
+extern {
+    fn extern_fn_1();
+}
+
+pub fn library_function() {
+    unsafe {
+        extern_fn_1();
+    }
+}
diff --git a/tests/run-make/raw-dylib-custom-dlltool/output.txt b/tests/run-make/raw-dylib-custom-dlltool/output.txt
new file mode 100644
index 00000000000..6dd9466d26d
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/output.txt
@@ -0,0 +1 @@
+Called dlltool via script.cmd
diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
new file mode 100644
index 00000000000..95f85c61c67
--- /dev/null
+++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd
@@ -0,0 +1,2 @@
+echo Called dlltool via script.cmd> %TMPDIR%\output.txt
+dlltool.exe %*
diff --git a/tests/run-make/raw-dylib-import-name-type/driver.rs b/tests/run-make/raw-dylib-import-name-type/driver.rs
index 9a3cd9ebe1b..6c1c212f187 100644
--- a/tests/run-make/raw-dylib-import-name-type/driver.rs
+++ b/tests/run-make/raw-dylib-import-name-type/driver.rs
@@ -1,4 +1,3 @@
-#![feature(raw_dylib)]
 #![feature(abi_vectorcall)]
 
 #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")]
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
index f72ded7d9f6..0c3125be6f5 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 extern crate raw_dylib_test;
 extern crate raw_dylib_test_wrapper;
 
diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
index 00c2c1c42d1..4877cb80aea 100644
--- a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
+++ b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs
@@ -1,5 +1,3 @@
-#![feature(raw_dylib)]
-
 #[link(name = "extern_1", kind = "raw-dylib")]
 extern {
     fn extern_fn_1();
diff --git a/tests/run-make/raw-dylib-link-ordinal/lib.rs b/tests/run-make/raw-dylib-link-ordinal/lib.rs
index bb25ac64c61..1bbb45bbc77 100644
--- a/tests/run-make/raw-dylib-link-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-link-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern {
     #[link_ordinal(13)]
diff --git a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
index b7921396a0f..74c5c7f8250 100644
--- a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
+++ b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "exporter", kind = "raw-dylib")]
 extern "stdcall" {
     #[link_ordinal(15)]
diff --git a/tests/rustdoc-js/slice-array.js b/tests/rustdoc-js/slice-array.js
new file mode 100644
index 00000000000..8c21e06dc4e
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.js
@@ -0,0 +1,65 @@
+// exact-check
+
+const QUERY = [
+    'R<primitive:slice<P>>',
+    'primitive:slice<R<P>>',
+    'R<primitive:slice<Q>>',
+    'primitive:slice<R<Q>>',
+    'R<primitive:array<Q>>',
+    'primitive:array<R<Q>>',
+    'primitive:array<TraitCat>',
+    'primitive:array<TraitDog>',
+];
+
+const EXPECTED = [
+    {
+        // R<primitive:slice<P>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'alpha' },
+        ],
+    },
+    {
+        // primitive:slice<R<P>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'alef' },
+        ],
+        'in_args': [],
+    },
+    {
+        // R<primitive:slice<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // primitive:slice<R<Q>>
+        'returned': [],
+        'in_args': [],
+    },
+    {
+        // R<primitive:array<Q>>
+        'returned': [
+            { 'path': 'slice_array', 'name': 'bet' },
+        ],
+        'in_args': [],
+    },
+    {
+        // primitive:array<R<Q>>
+        'returned': [],
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'beta' },
+        ],
+    },
+    {
+        // primitive::array<TraitCat>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+    {
+        // primitive::array<TraitDog>
+        'in_args': [
+            { 'path': 'slice_array', 'name': 'gamma' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/slice-array.rs b/tests/rustdoc-js/slice-array.rs
new file mode 100644
index 00000000000..2523b21cfaa
--- /dev/null
+++ b/tests/rustdoc-js/slice-array.rs
@@ -0,0 +1,16 @@
+pub struct P;
+pub struct Q;
+pub struct R<T>(T);
+
+// returns test
+pub fn alef() -> &'static [R<P>] { loop {} }
+pub fn bet() -> R<[Q; 32]> { loop {} }
+
+// in_args test
+pub fn alpha(_x: R<&'static [P]>) { loop {} }
+pub fn beta(_x: [R<Q>; 32]) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: [T; 32]) {}
diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.stderr b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
index 1db8e1d91c2..03fb6f96fb5 100644
--- a/tests/rustdoc-ui/check-cfg/check-cfg.stderr
+++ b/tests/rustdoc-ui/check-cfg/check-cfg.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/check-cfg.rs:5:7
    |
 LL | #[cfg(uniz)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.stderr b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
index 9770be2f191..f84543c2072 100644
--- a/tests/rustdoc-ui/doctest/check-cfg-test.stderr
+++ b/tests/rustdoc-ui/doctest/check-cfg-test.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "invalid")]
    |       ^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: test
+   = note: expected values for `feature` are: `test`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/rustdoc-ui/ice-bug-report-url.rs b/tests/rustdoc-ui/ice-bug-report-url.rs
new file mode 100644
index 00000000000..cc066447d31
--- /dev/null
+++ b/tests/rustdoc-ui/ice-bug-report-url.rs
@@ -0,0 +1,14 @@
+// compile-flags: -Ztreat-err-as-bug
+// failure-status: 101
+// error-pattern: aborting due to
+// error-pattern: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
+
+// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
+// normalize-stderr-test "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}"
+// normalize-stderr-test "thread.*panicked at .*, compiler.*" -> "thread panicked at 'aborting due to `-Z treat-err-as-bug`'"
+// normalize-stderr-test "\s*\d{1,}: .*\n" -> ""
+// normalize-stderr-test "\s at .*\n" -> ""
+// normalize-stderr-test ".*note: Some details are omitted.*\n" -> ""
+
+fn wrong()
+//~^ ERROR expected one of
diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr
new file mode 100644
index 00000000000..cfb73a9b919
--- /dev/null
+++ b/tests/rustdoc-ui/ice-bug-report-url.stderr
@@ -0,0 +1,16 @@
+error: expected one of `->`, `where`, or `{`, found `<eof>`
+  --> $DIR/ice-bug-report-url.rs:13:10
+   |
+LL | fn wrong()
+   |          ^ expected one of `->`, `where`, or `{`
+
+thread panicked at 'aborting due to `-Z treat-err-as-bug`'
+stack backtrace:
+error: the compiler unexpectedly panicked. this is a bug.
+
+note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
+
+note: rustc {version} running on {platform}
+
+query stack during panic:
+end of query stack
diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs
index b84b5a717b7..a52562d78f8 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs
@@ -8,6 +8,6 @@ trait Trait {
 }
 
 fn bar<T: Trait<methid(): Send>>() {}
-//~^ ERROR cannot find associated function `methid` in trait `Trait`
+//~^ ERROR cannot find associated function `methid` for `Trait`
 
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
index 954d9f74767..5b1c4cb0b2c 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr
@@ -7,7 +7,7 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
    = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: cannot find associated function `methid` in trait `Trait`
+error: cannot find associated function `methid` for `Trait`
   --> $DIR/missing.rs:10:17
    |
 LL | fn bar<T: Trait<methid(): Send>>() {}
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
new file mode 100644
index 00000000000..028e526b5f5
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs
@@ -0,0 +1,32 @@
+// edition:2021
+
+#![feature(async_fn_in_trait, return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+
+trait Super1<'a> {
+    async fn test();
+}
+impl Super1<'_> for () {
+    async fn test() {}
+}
+
+trait Super2 {
+    async fn test();
+}
+impl Super2 for () {
+    async fn test() {}
+}
+
+trait Foo: for<'a> Super1<'a> + Super2 {}
+impl Foo for () {}
+
+fn test<T>()
+where
+    T: Foo<test(): Send>,
+    //~^ ERROR ambiguous associated function `test` for `Foo`
+{
+}
+
+fn main() {
+    test::<()>();
+}
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
new file mode 100644
index 00000000000..5bc8dbde4bc
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr
@@ -0,0 +1,19 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/super-method-bound-ambig.rs:3:31
+   |
+LL | #![feature(async_fn_in_trait, return_type_notation)]
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: ambiguous associated function `test` for `Foo`
+  --> $DIR/super-method-bound-ambig.rs:25:12
+   |
+LL |     T: Foo<test(): Send>,
+   |            ^^^^^^^^^^^^
+   |
+   = note: `test` is declared in two supertraits: `Super2` and `Super1<'a>`
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs
new file mode 100644
index 00000000000..58ea3578db6
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs
@@ -0,0 +1,25 @@
+// edition:2021
+// check-pass
+
+#![feature(async_fn_in_trait, return_type_notation)]
+//~^ WARN the feature `return_type_notation` is incomplete
+
+trait Super<'a> {
+    async fn test();
+}
+impl Super<'_> for () {
+    async fn test() {}
+}
+
+trait Foo: for<'a> Super<'a> {}
+impl Foo for () {}
+
+fn test<T>()
+where
+    T: Foo<test(): Send>,
+{
+}
+
+fn main() {
+    test::<()>();
+}
diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.stderr
new file mode 100644
index 00000000000..ac0668d3c44
--- /dev/null
+++ b/tests/ui/async-await/return-type-notation/super-method-bound.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/super-method-bound.rs:4:31
+   |
+LL | #![feature(async_fn_in_trait, return_type_notation)]
+   |                               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr
index 5ca4d3b3de7..70a967c0e5f 100644
--- a/tests/ui/check-cfg/compact-values.stderr
+++ b/tests/ui/check-cfg/compact-values.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target(os = "linux", arch = "X"))]
    |                            ^^^^^^^^^^
    |
-   = note: expected values for `target_arch` are: aarch64, arm, avr, bpf, hexagon, loongarch64, m68k, mips, mips64, msp430, nvptx64, powerpc, powerpc64, riscv32, riscv64, s390x, sparc, sparc64, wasm32, wasm64, x86, x86_64
+   = note: expected values for `target_arch` are: `aarch64`, `arm`, `avr`, `bpf`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips64`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
new file mode 100644
index 00000000000..49e127d079a
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -0,0 +1,31 @@
+// check-pass
+// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options
+
+#[cfg(featur)]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(featur = "fo")]
+//~^ WARNING unexpected `cfg` condition name
+fn feature() {}
+
+#[cfg(feature = "foo")]
+fn feature() {}
+
+#[cfg(no_value)]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_value = "foo")]
+//~^ WARNING unexpected `cfg` condition name
+fn no_values() {}
+
+#[cfg(no_values = "bar")]
+//~^ WARNING unexpected `cfg` condition value
+fn no_values() {}
+
+fn main() {}
diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr
new file mode 100644
index 00000000000..8b9fef09d09
--- /dev/null
+++ b/tests/ui/check-cfg/diagnotics.stderr
@@ -0,0 +1,62 @@
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:4:7
+   |
+LL | #[cfg(featur)]
+   |       ^^^^^^ help: there is a config with a similar name: `feature`
+   |
+   = help: expected values for `feature` are: `foo`
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:8:7
+   |
+LL | #[cfg(featur = "foo")]
+   |       ^^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and value
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:12:7
+   |
+LL | #[cfg(featur = "fo")]
+   |       ^^^^^^^^^^^^^
+   |
+   = help: expected values for `feature` are: `foo`
+help: there is a config with a similar name and different values
+   |
+LL | #[cfg(feature = "foo")]
+   |       ~~~~~~~~~~~~~~~
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:19:7
+   |
+LL | #[cfg(no_value)]
+   |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
+
+warning: unexpected `cfg` condition name
+  --> $DIR/diagnotics.rs:23:7
+   |
+LL | #[cfg(no_value = "foo")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+help: there is a config with a similar name and no value
+   |
+LL | #[cfg(no_values)]
+   |       ~~~~~~~~~
+
+warning: unexpected `cfg` condition value
+  --> $DIR/diagnotics.rs:27:7
+   |
+LL | #[cfg(no_values = "bar")]
+   |       ^^^^^^^^^--------
+   |                |
+   |                help: remove the value
+   |
+   = note: no expected value for `no_values`
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/invalid-cfg-name.stderr
index 2bd1821c942..ed09f8cb66d 100644
--- a/tests/ui/check-cfg/invalid-cfg-name.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-name.stderr
@@ -2,7 +2,7 @@ warning: unexpected `cfg` condition name
   --> $DIR/invalid-cfg-name.rs:7:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/invalid-cfg-value.stderr
index 83383ea61a4..776d264a7ad 100644
--- a/tests/ui/check-cfg/invalid-cfg-value.stderr
+++ b/tests/ui/check-cfg/invalid-cfg-value.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "sedre")]
    |       ^^^^^^^^^^-------
    |                 |
-   |                 help: did you mean: `"serde"`
+   |                 help: there is a expected value with a similar name: `"serde"`
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: full, serde
+   = note: expected values for `feature` are: `full`, `serde`
 
 warning: unexpected condition value `rand` for condition name `feature`
    |
diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs
index 4e488fc03ec..9adf5c46e43 100644
--- a/tests/ui/check-cfg/mix.rs
+++ b/tests/ui/check-cfg/mix.rs
@@ -12,6 +12,10 @@ fn do_windows_stuff() {}
 //~^ WARNING unexpected `cfg` condition name
 fn do_windows_stuff() {}
 
+#[cfg(feature)]
+//~^ WARNING unexpected `cfg` condition value
+fn no_feature() {}
+
 #[cfg(feature = "foo")]
 fn use_foo() {}
 
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 9cf887ec788..07c514aed52 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -2,28 +2,36 @@ warning: unexpected `cfg` condition name
   --> $DIR/mix.rs:11:7
    |
 LL | #[cfg(widnows)]
-   |       ^^^^^^^ help: did you mean: `windows`
+   |       ^^^^^^^ help: there is a config with a similar name: `windows`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:18:7
+  --> $DIR/mix.rs:15:7
    |
-LL | #[cfg(feature = "bar")]
-   |       ^^^^^^^^^^^^^^^
+LL | #[cfg(feature)]
+   |       ^^^^^^^- help: specify a config value: `= "foo"`
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
   --> $DIR/mix.rs:22:7
    |
+LL | #[cfg(feature = "bar")]
+   |       ^^^^^^^^^^^^^^^
+   |
+   = note: expected values for `feature` are: `foo`
+
+warning: unexpected `cfg` condition value
+  --> $DIR/mix.rs:26:7
+   |
 LL | #[cfg(feature = "zebra")]
    |       ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:26:12
+  --> $DIR/mix.rs:30:12
    |
 LL | #[cfg_attr(uu, test)]
    |            ^^
@@ -37,146 +45,146 @@ warning: unexpected `unknown_name` as condition name
    = help: was set with `--cfg` but isn't in the `--check-cfg` expected names
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:35:10
+  --> $DIR/mix.rs:39:10
    |
 LL |     cfg!(widnows);
-   |          ^^^^^^^ help: did you mean: `windows`
+   |          ^^^^^^^ help: there is a config with a similar name: `windows`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:38:10
+  --> $DIR/mix.rs:42:10
    |
 LL |     cfg!(feature = "bar");
    |          ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:40:10
+  --> $DIR/mix.rs:44:10
    |
 LL |     cfg!(feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:42:10
+  --> $DIR/mix.rs:46:10
    |
 LL |     cfg!(xxx = "foo");
    |          ^^^^^^^^^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:44:10
+  --> $DIR/mix.rs:48:10
    |
 LL |     cfg!(xxx);
    |          ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:46:14
+  --> $DIR/mix.rs:50:14
    |
 LL |     cfg!(any(xxx, windows));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:48:14
+  --> $DIR/mix.rs:52:14
    |
 LL |     cfg!(any(feature = "bad", windows));
    |              ^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:50:23
+  --> $DIR/mix.rs:54:23
    |
 LL |     cfg!(any(windows, xxx));
    |                       ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:52:20
+  --> $DIR/mix.rs:56:20
    |
 LL |     cfg!(all(unix, xxx));
    |                    ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:14
+  --> $DIR/mix.rs:58:14
    |
 LL |     cfg!(all(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:54:18
+  --> $DIR/mix.rs:58:18
    |
 LL |     cfg!(all(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:14
+  --> $DIR/mix.rs:61:14
    |
 LL |     cfg!(any(aa, bb));
    |              ^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:57:18
+  --> $DIR/mix.rs:61:18
    |
 LL |     cfg!(any(aa, bb));
    |                  ^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:60:20
+  --> $DIR/mix.rs:64:20
    |
 LL |     cfg!(any(unix, feature = "zebra"));
    |                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:62:14
+  --> $DIR/mix.rs:66:14
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |              ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:62:19
+  --> $DIR/mix.rs:66:19
    |
 LL |     cfg!(any(xxx, feature = "zebra"));
    |                   ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:14
+  --> $DIR/mix.rs:69:14
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |              ^^^
 
 warning: unexpected `cfg` condition name
-  --> $DIR/mix.rs:65:25
+  --> $DIR/mix.rs:69:25
    |
 LL |     cfg!(any(xxx, unix, xxx));
    |                         ^^^
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:14
+  --> $DIR/mix.rs:72:14
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |              ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:33
+  --> $DIR/mix.rs:72:33
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                 ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
 warning: unexpected `cfg` condition value
-  --> $DIR/mix.rs:68:52
+  --> $DIR/mix.rs:72:52
    |
 LL |     cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra"));
    |                                                    ^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: foo
+   = note: expected values for `feature` are: `foo`
 
-warning: 27 warnings emitted
+warning: 28 warnings emitted
 
diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-values.stderr
index 8c926d187fe..ffa87dc58f2 100644
--- a/tests/ui/check-cfg/no-values.stderr
+++ b/tests/ui/check-cfg/no-values.stderr
@@ -2,7 +2,9 @@ warning: unexpected `cfg` condition value
   --> $DIR/no-values.rs:6:7
    |
 LL | #[cfg(feature = "foo")]
-   |       ^^^^^^^^^^^^^^^
+   |       ^^^^^^^--------
+   |              |
+   |              help: remove the value
    |
    = note: no expected value for `feature`
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr
index b58d2970773..eb81535e3ed 100644
--- a/tests/ui/check-cfg/values-target-json.stderr
+++ b/tests/ui/check-cfg/values-target-json.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, ericos, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `ericos`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index bdbe4d29d30..34c5d6172d9 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(target_oz = "linux")]
    |       ---------^^^^^^^^^^
    |       |
-   |       help: did you mean: `target_os`
+   |       help: there is a config with a similar name: `target_os`
    |
    = note: `#[warn(unexpected_cfgs)]` on by default
 
@@ -14,13 +14,13 @@ warning: unexpected `cfg` condition name
 LL | #[cfg(features = "foo")]
    |       --------^^^^^^^^
    |       |
-   |       help: did you mean: `feature`
+   |       help: there is a config with a similar name: `feature`
 
 warning: unexpected `cfg` condition name
   --> $DIR/well-known-names.rs:20:7
    |
 LL | #[cfg(uniw)]
-   |       ^^^^ help: did you mean: `unix`
+   |       ^^^^ help: there is a config with a similar name: `unix`
 
 warning: 3 warnings emitted
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 69d799783a9..2d18cb82e03 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -4,9 +4,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_os = "linuz")]
    |       ^^^^^^^^^^^^-------
    |                   |
-   |                   help: did you mean: `"linux"`
+   |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: aix, android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, nto, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vita, vxworks, wasi, watchos, windows, xous
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value
@@ -15,9 +15,9 @@ warning: unexpected `cfg` condition value
 LL | #[cfg(target_has_atomic = "0")]
    |       ^^^^^^^^^^^^^^^^^^^^---
    |                           |
-   |                           help: did you mean: `"8"`
+   |                           help: there is a expected value with a similar name: `"8"`
    |
-   = note: expected values for `target_has_atomic` are: 128, 16, 32, 64, 8, ptr
+   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
 
 warning: unexpected `cfg` condition value
   --> $DIR/well-known-values.rs:21:7
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad1.stderr b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
new file mode 100644
index 00000000000..3b506c7e7ec
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.bad1.stderr
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:27:18
+   |
+LL | impl<T> Drop for DropMe<T>
+   |                  ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider further restricting type parameter `T`
+   |
+LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
+   |                 ~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:32:13
+   |
+LL |     fn drop(&mut self) {}
+   |             ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider further restricting type parameter `T`
+   |
+LL |     [T; 1]: Copy, T: std::marker::Copy // But `[T; 1]: Copy` does not imply `T: Copy`
+   |                 ~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.bad2.stderr b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
new file mode 100644
index 00000000000..832af3e521a
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.bad2.stderr
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:37:18
+   |
+LL | impl<T> Drop for DropMe<T>
+   |                  ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> Drop for DropMe<T>
+   |       +++++++++++++++++++
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/explicit-drop-bounds.rs:40:13
+   |
+LL |     fn drop(&mut self) {}
+   |             ^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `DropMe`
+  --> $DIR/explicit-drop-bounds.rs:7:18
+   |
+LL | struct DropMe<T: Copy>(T);
+   |                  ^^^^ required by this bound in `DropMe`
+help: consider restricting type parameter `T`
+   |
+LL | impl<T: std::marker::Copy> Drop for DropMe<T>
+   |       +++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/dropck/explicit-drop-bounds.rs b/tests/ui/dropck/explicit-drop-bounds.rs
new file mode 100644
index 00000000000..ab6f33c0999
--- /dev/null
+++ b/tests/ui/dropck/explicit-drop-bounds.rs
@@ -0,0 +1,44 @@
+// revisions: good1 good2 bad1 bad2
+//[good1] check-pass
+//[good2] check-pass
+
+use std::ops::Drop;
+
+struct DropMe<T: Copy>(T);
+
+#[cfg(good1)]
+impl<T> Drop for DropMe<T>
+where
+    T: Copy + Clone,
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl<T> Drop for DropMe<T>
+where
+    T: Copy,
+    [T; 1]: Copy, // Trivial bound implied by `T: Copy`
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad1)]
+impl<T> Drop for DropMe<T>
+//[bad1]~^ ERROR the trait bound `T: Copy` is not satisfied
+where
+    [T; 1]: Copy, // But `[T; 1]: Copy` does not imply `T: Copy`
+{
+    fn drop(&mut self) {}
+    //[bad1]~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+#[cfg(bad2)]
+impl<T> Drop for DropMe<T>
+//[bad2]~^ ERROR the trait bound `T: Copy` is not satisfied
+{
+    fn drop(&mut self) {}
+    //[bad2]~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/explicit-implied-outlives.bad1.stderr b/tests/ui/dropck/explicit-implied-outlives.bad1.stderr
new file mode 100644
index 00000000000..bf6d70e7d37
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.bad1.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
+  --> $DIR/explicit-implied-outlives.rs:28:8
+   |
+LL |     T: 'static,
+   |        ^^^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/explicit-implied-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, T>(&'a T);
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/explicit-implied-outlives.bad2.stderr b/tests/ui/dropck/explicit-implied-outlives.bad2.stderr
new file mode 100644
index 00000000000..27a15170bdd
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.bad2.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `'a: 'static` but the struct it is implemented for does not
+  --> $DIR/explicit-implied-outlives.rs:37:9
+   |
+LL |     'a: 'static,
+   |         ^^^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/explicit-implied-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, T>(&'a T);
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/explicit-implied-outlives.rs b/tests/ui/dropck/explicit-implied-outlives.rs
new file mode 100644
index 00000000000..fa446591f3d
--- /dev/null
+++ b/tests/ui/dropck/explicit-implied-outlives.rs
@@ -0,0 +1,43 @@
+// revisions: good1 good2 bad1 bad2
+//[good1] check-pass
+//[good2] check-pass
+
+use std::ops::Drop;
+
+struct DropMe<'a, T>(&'a T);
+
+#[cfg(good1)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    T: 'a, // Implied by struct, explicit on impl
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    'static: 'a, // Trivial bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad1)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    T: 'static,
+    //[bad1]~^ ERROR `Drop` impl requires `T: 'static`
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad2)]
+impl<'a, T> Drop for DropMe<'a, T>
+where
+    'a: 'static,
+    //[bad2]~^ ERROR `Drop` impl requires `'a: 'static`
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/transitive-outlives-2.rs b/tests/ui/dropck/transitive-outlives-2.rs
new file mode 100644
index 00000000000..87154e25d40
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives-2.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+use std::marker::PhantomData;
+use std::ops::Drop;
+
+// a >= b >= c >= a implies a = b = c
+struct DropMe<'a: 'b, 'b: 'c, 'c: 'a>(
+    PhantomData<&'a ()>,
+    PhantomData<&'b ()>,
+    PhantomData<&'c ()>,
+);
+
+// a >= b, a >= c, b >= a, c >= a implies a = b = c
+impl<'a: 'b + 'c, 'b: 'a, 'c: 'a> Drop for DropMe<'a, 'b, 'c> {
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/transitive-outlives.bad.stderr b/tests/ui/dropck/transitive-outlives.bad.stderr
new file mode 100644
index 00000000000..da5088b27b4
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives.bad.stderr
@@ -0,0 +1,15 @@
+error[E0367]: `Drop` impl requires `'a: 'c` but the struct it is implemented for does not
+  --> $DIR/transitive-outlives.rs:20:9
+   |
+LL |     'a: 'c,
+   |         ^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/transitive-outlives.rs:7:1
+   |
+LL | struct DropMe<'a, 'b: 'a, 'c: 'b>(PhantomData<&'a ()>, PhantomData<&'b ()>, PhantomData<&'c ()>);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/dropck/transitive-outlives.rs b/tests/ui/dropck/transitive-outlives.rs
new file mode 100644
index 00000000000..d071664abde
--- /dev/null
+++ b/tests/ui/dropck/transitive-outlives.rs
@@ -0,0 +1,26 @@
+// revisions: good bad
+//[good] check-pass
+
+use std::marker::PhantomData;
+use std::ops::Drop;
+
+struct DropMe<'a, 'b: 'a, 'c: 'b>(PhantomData<&'a ()>, PhantomData<&'b ()>, PhantomData<&'c ()>);
+
+#[cfg(good)]
+impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
+where
+    'c: 'a,
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(bad)]
+impl<'a, 'b, 'c> Drop for DropMe<'a, 'b, 'c>
+where
+    'a: 'c,
+    //[bad]~^ ERROR `Drop` impl requires `'a: 'c`
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/trivial-impl-bounds.rs b/tests/ui/dropck/trivial-impl-bounds.rs
new file mode 100644
index 00000000000..a8f5d2c354b
--- /dev/null
+++ b/tests/ui/dropck/trivial-impl-bounds.rs
@@ -0,0 +1,34 @@
+// revisions: good1 good2 good3
+// check-pass
+
+use std::ops::Drop;
+
+struct Foo;
+
+const X: usize = 1;
+
+#[cfg(good1)]
+impl Drop for Foo
+where
+    [(); X]:, // Trivial WF bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good2)]
+impl Drop for Foo
+where
+    for<'a> &'a (): Copy, // Trivial trait bound
+{
+    fn drop(&mut self) {}
+}
+
+#[cfg(good3)]
+impl Drop for Foo
+where
+    for<'a> &'a (): 'a, // Trivial outlives bound
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/extern-flag/auxiliary/panic_handler.rs b/tests/ui/extern-flag/auxiliary/panic_handler.rs
new file mode 100644
index 00000000000..a625761a838
--- /dev/null
+++ b/tests/ui/extern-flag/auxiliary/panic_handler.rs
@@ -0,0 +1,17 @@
+#![feature(lang_items)]
+#![no_std]
+
+// Since `rustc` generally passes `-nodefaultlibs` to the linker,
+// Rust programs link necessary system libraries via `#[link()]`
+// attributes in the `libc` crate. `libc` is a dependency of `std`,
+// but as we are `#![no_std]`, we need to include it manually.
+#![feature(rustc_private)]
+extern crate libc;
+
+#[panic_handler]
+pub fn begin_panic_handler(_info: &core::panic::PanicInfo<'_>) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/tests/ui/extern-flag/force-extern.rs b/tests/ui/extern-flag/force-extern.rs
new file mode 100644
index 00000000000..f56b5378223
--- /dev/null
+++ b/tests/ui/extern-flag/force-extern.rs
@@ -0,0 +1,9 @@
+// check-pass
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// aux-crate:force:panic_handler=panic_handler.rs
+// compile-flags: -Zunstable-options --crate-type dylib
+// edition:2018
+
+#![no_std]
+
+fn foo() {}
diff --git a/tests/ui/extern-flag/no-force-extern.rs b/tests/ui/extern-flag/no-force-extern.rs
new file mode 100644
index 00000000000..ce9cbfe1cd2
--- /dev/null
+++ b/tests/ui/extern-flag/no-force-extern.rs
@@ -0,0 +1,10 @@
+// aux-crate:panic_handler=panic_handler.rs
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// compile_flags: -Zunstable-options --crate-type dylib
+// error-pattern: `#[panic_handler]` function required, but not found
+// dont-check-compiler-stderr
+// edition: 2018
+
+#![no_std]
+
+fn foo() {}
diff --git a/tests/ui/extern-flag/redundant-force-extern.rs b/tests/ui/extern-flag/redundant-force-extern.rs
new file mode 100644
index 00000000000..a4091616dd5
--- /dev/null
+++ b/tests/ui/extern-flag/redundant-force-extern.rs
@@ -0,0 +1,11 @@
+// check-pass
+// ignore-cross-compile (needs dylibs and compiletest doesn't have a more specific header)
+// aux-crate:force:panic_handler=panic_handler.rs
+// compile-flags: -Zunstable-options --crate-type dylib
+// edition:2018
+
+#![no_std]
+
+extern crate panic_handler;
+
+fn foo() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
deleted file mode 100644
index fc47a9061d3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// only-x86
-#[link(name = "foo")]
-extern "C" {
-    #[link_ordinal(42)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    fn foo();
-    #[link_ordinal(5)]
-    //~^ ERROR: `#[link_ordinal]` is unstable on x86
-    static mut imported_variable: i32;
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
deleted file mode 100644
index 0e900760d24..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:4:5
-   |
-LL |     #[link_ordinal(42)]
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: `#[link_ordinal]` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-2.rs:7:5
-   |
-LL |     #[link_ordinal(5)]
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
deleted file mode 100644
index 295f502d6a3..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-//~^ ERROR link kind `raw-dylib` is unstable on x86
-//~| ERROR import name type is unstable
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
deleted file mode 100644
index d6b165b7610..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error[E0658]: import name type is unstable
-  --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61
-   |
-LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")]
-   |                                                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.rs b/tests/ui/feature-gates/feature-gate-raw-dylib.rs
deleted file mode 100644
index 291cca8fd25..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// only-windows
-// only-x86
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: link kind `raw-dylib` is unstable on x86
-extern "C" {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
deleted file mode 100644
index f02241e4908..00000000000
--- a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: link kind `raw-dylib` is unstable on x86
-  --> $DIR/feature-gate-raw-dylib.rs:3:29
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   |                             ^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/layout/debug.rs b/tests/ui/layout/debug.rs
index a282e71235c..46171880a6f 100644
--- a/tests/ui/layout/debug.rs
+++ b/tests/ui/layout/debug.rs
@@ -1,8 +1,9 @@
 // normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
-#![feature(never_type, rustc_attrs, type_alias_impl_trait)]
+#![feature(never_type, rustc_attrs, type_alias_impl_trait, repr_simd)]
 #![crate_type = "lib"]
 
 #[rustc_layout(debug)]
+#[derive(Copy, Clone)]
 enum E { Foo, Bar(!, i32, i32) } //~ ERROR: layout_of
 
 #[rustc_layout(debug)]
@@ -17,6 +18,51 @@ type Test = Result<i32, i32>; //~ ERROR: layout_of
 #[rustc_layout(debug)]
 type T = impl std::fmt::Debug; //~ ERROR: layout_of
 
+#[rustc_layout(debug)]
+pub union V { //~ ERROR: layout_of
+    a: [u16; 0],
+    b: u8,
+}
+
+#[rustc_layout(debug)]
+pub union W { //~ ERROR: layout_of
+    b: u8,
+    a: [u16; 0],
+}
+
+#[rustc_layout(debug)]
+pub union Y { //~ ERROR: layout_of
+    b: [u8; 0],
+    a: [u16; 0],
+}
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P1 { x: u32 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P2 { x: (u32, u32) } //~ ERROR: layout_of
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct F32x4(f32, f32, f32, f32);
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P3 { x: F32x4 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P4 { x: E } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(packed(1))]
+union P5 { zst: [u16; 0], byte: u8 } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+type X = std::mem::MaybeUninit<u8>; //~ ERROR: layout_of
+
 fn f() -> T {
     0i32
 }
diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr
index c5e1c41d130..b9fa1b299e9 100644
--- a/tests/ui/layout/debug.stderr
+++ b/tests/ui/layout/debug.stderr
@@ -81,7 +81,7 @@ error: layout_of(E) = Layout {
                ],
            },
        }
-  --> $DIR/debug.rs:6:1
+  --> $DIR/debug.rs:7:1
    |
 LL | enum E { Foo, Bar(!, i32, i32) }
    | ^^^^^^
@@ -125,7 +125,7 @@ error: layout_of(S) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:9:1
+  --> $DIR/debug.rs:10:1
    |
 LL | struct S { f1: i32, f2: (), f3: i32 }
    | ^^^^^^^^
@@ -147,7 +147,7 @@ error: layout_of(U) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:12:1
+  --> $DIR/debug.rs:13:1
    |
 LL | union U { f1: (i32, i32), f3: i32 }
    | ^^^^^^^
@@ -276,7 +276,7 @@ error: layout_of(std::result::Result<i32, i32>) = Layout {
                ],
            },
        }
-  --> $DIR/debug.rs:15:1
+  --> $DIR/debug.rs:16:1
    |
 LL | type Test = Result<i32, i32>;
    | ^^^^^^^^^
@@ -302,10 +302,218 @@ error: layout_of(i32) = Layout {
                index: 0,
            },
        }
-  --> $DIR/debug.rs:18:1
+  --> $DIR/debug.rs:19:1
    |
 LL | type T = impl std::fmt::Debug;
    | ^^^^^^
 
-error: aborting due to 5 previous errors
+error: layout_of(V) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:22:1
+   |
+LL | pub union V {
+   | ^^^^^^^^^^^
+
+error: layout_of(W) = Layout {
+           size: Size(2 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:28:1
+   |
+LL | pub union W {
+   | ^^^^^^^^^^^
+
+error: layout_of(Y) = Layout {
+           size: Size(0 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(2 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:34:1
+   |
+LL | pub union Y {
+   | ^^^^^^^^^^^
+
+error: layout_of(P1) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:41:1
+   |
+LL | union P1 { x: u32 }
+   | ^^^^^^^^
+
+error: layout_of(P2) = Layout {
+           size: Size(8 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:45:1
+   |
+LL | union P2 { x: (u32, u32) }
+   | ^^^^^^^^
+
+error: layout_of(P3) = Layout {
+           size: Size(16 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:53:1
+   |
+LL | union P3 { x: F32x4 }
+   | ^^^^^^^^
+
+error: layout_of(P4) = Layout {
+           size: Size(12 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           fields: Union(
+               1,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:57:1
+   |
+LL | union P4 { x: E }
+   | ^^^^^^^^
+
+error: layout_of(P5) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Scalar(
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:61:1
+   |
+LL | union P5 { zst: [u16; 0], byte: u8 }
+   | ^^^^^^^^
+
+error: layout_of(std::mem::MaybeUninit<u8>) = Layout {
+           size: Size(1 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           abi: Scalar(
+               Union {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+               },
+           ),
+           fields: Union(
+               2,
+           ),
+           largest_niche: None,
+           variants: Single {
+               index: 0,
+           },
+       }
+  --> $DIR/debug.rs:64:1
+   |
+LL | type X = std::mem::MaybeUninit<u8>;
+   | ^^^^^^
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/lint/internal/trivial-diagnostics.rs b/tests/ui/lint/internal/trivial-diagnostics.rs
new file mode 100644
index 00000000000..e536e1164fc
--- /dev/null
+++ b/tests/ui/lint/internal/trivial-diagnostics.rs
@@ -0,0 +1,8 @@
+// compile-flags: -Zunstable-options
+
+pub fn issue_111280() {
+    struct_span_err(msg).emit(); //~ ERROR cannot find value `msg`
+    //~^ ERROR cannot find function `struct_span_err`
+}
+
+fn main() {}
diff --git a/tests/ui/lint/internal/trivial-diagnostics.stderr b/tests/ui/lint/internal/trivial-diagnostics.stderr
new file mode 100644
index 00000000000..d47a7dae023
--- /dev/null
+++ b/tests/ui/lint/internal/trivial-diagnostics.stderr
@@ -0,0 +1,15 @@
+error[E0425]: cannot find value `msg` in this scope
+  --> $DIR/trivial-diagnostics.rs:4:21
+   |
+LL |     struct_span_err(msg).emit();
+   |                     ^^^ not found in this scope
+
+error[E0425]: cannot find function `struct_span_err` in this scope
+  --> $DIR/trivial-diagnostics.rs:4:5
+   |
+LL |     struct_span_err(msg).emit();
+   |     ^^^^^^^^^^^^^^^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/lint/lint-missing-doc.rs b/tests/ui/lint/lint-missing-doc.rs
index 4a234d2651a..e4c9f8f559b 100644
--- a/tests/ui/lint/lint-missing-doc.rs
+++ b/tests/ui/lint/lint-missing-doc.rs
@@ -3,6 +3,7 @@
 #![deny(missing_docs)]
 #![allow(dead_code)]
 #![feature(associated_type_defaults, extern_types)]
+#![feature(trait_alias)]
 
 //! Some garbage docs for the crate here
 #![doc="More garbage"]
@@ -202,4 +203,6 @@ extern "C" {
     //~^ ERROR: missing documentation for a foreign type
 }
 
+pub trait T = Sync; //~ ERROR: missing documentation for a trait alias
+
 fn main() {}
diff --git a/tests/ui/lint/lint-missing-doc.stderr b/tests/ui/lint/lint-missing-doc.stderr
index 733d062a08b..c94bd3b8dfb 100644
--- a/tests/ui/lint/lint-missing-doc.stderr
+++ b/tests/ui/lint/lint-missing-doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/lint-missing-doc.rs:11:1
+  --> $DIR/lint-missing-doc.rs:12:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^
@@ -11,142 +11,148 @@ LL | #![deny(missing_docs)]
    |         ^^^^^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/lint-missing-doc.rs:18:1
+  --> $DIR/lint-missing-doc.rs:19:1
    |
 LL | pub struct PubFoo {
    | ^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/lint-missing-doc.rs:19:5
+  --> $DIR/lint-missing-doc.rs:20:5
    |
 LL |     pub a: isize,
    |     ^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/lint-missing-doc.rs:30:1
+  --> $DIR/lint-missing-doc.rs:31:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:34:1
+  --> $DIR/lint-missing-doc.rs:35:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^
 
 error: missing documentation for a trait
-  --> $DIR/lint-missing-doc.rs:52:1
+  --> $DIR/lint-missing-doc.rs:53:1
    |
 LL | pub trait C {
    | ^^^^^^^^^^^
 
 error: missing documentation for a method
-  --> $DIR/lint-missing-doc.rs:53:5
+  --> $DIR/lint-missing-doc.rs:54:5
    |
 LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
 
 error: missing documentation for a method
-  --> $DIR/lint-missing-doc.rs:54:5
+  --> $DIR/lint-missing-doc.rs:55:5
    |
 LL |     fn foo_with_impl(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/lint-missing-doc.rs:55:5
+  --> $DIR/lint-missing-doc.rs:56:5
    |
 LL |     fn foo_no_self();
    |     ^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/lint-missing-doc.rs:56:5
+  --> $DIR/lint-missing-doc.rs:57:5
    |
 LL |     fn foo_no_self_with_impl() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/lint-missing-doc.rs:66:5
+  --> $DIR/lint-missing-doc.rs:67:5
    |
 LL |     type AssociatedType;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/lint-missing-doc.rs:67:5
+  --> $DIR/lint-missing-doc.rs:68:5
    |
 LL |     type AssociatedTypeDef = Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/lint-missing-doc.rs:83:5
+  --> $DIR/lint-missing-doc.rs:84:5
    |
 LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/lint-missing-doc.rs:120:1
+  --> $DIR/lint-missing-doc.rs:121:1
    |
 LL | pub enum PubBaz {
    | ^^^^^^^^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/lint-missing-doc.rs:121:5
+  --> $DIR/lint-missing-doc.rs:122:5
    |
 LL |     PubBazA {
    |     ^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/lint-missing-doc.rs:122:9
+  --> $DIR/lint-missing-doc.rs:123:9
    |
 LL |         a: isize,
    |         ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/lint-missing-doc.rs:153:1
+  --> $DIR/lint-missing-doc.rs:154:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/lint-missing-doc.rs:163:1
+  --> $DIR/lint-missing-doc.rs:164:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:169:5
+  --> $DIR/lint-missing-doc.rs:170:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:170:5
+  --> $DIR/lint-missing-doc.rs:171:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:176:9
+  --> $DIR/lint-missing-doc.rs:177:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/lint-missing-doc.rs:191:5
+  --> $DIR/lint-missing-doc.rs:192:5
    |
 LL |     pub fn extern_fn_undocumented(f: f32) -> f32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/lint-missing-doc.rs:196:5
+  --> $DIR/lint-missing-doc.rs:197:5
    |
 LL |     pub static EXTERN_STATIC_UNDOCUMENTED: u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a foreign type
-  --> $DIR/lint-missing-doc.rs:201:5
+  --> $DIR/lint-missing-doc.rs:202:5
    |
 LL |     pub type ExternTyUndocumented;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 24 previous errors
+error: missing documentation for a trait alias
+  --> $DIR/lint-missing-doc.rs:206:1
+   |
+LL | pub trait T = Sync;
+   | ^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
 
diff --git a/tests/ui/optimization-remark.rs b/tests/ui/optimization-remark.rs
index 4f651b1dcbc..8fd30466f43 100644
--- a/tests/ui/optimization-remark.rs
+++ b/tests/ui/optimization-remark.rs
@@ -13,7 +13,7 @@
 // [merge1] compile-flags: -Cremark=all    -Cremark=giraffe
 // [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
 //
-// error-pattern: inline: 'f' not inlined into 'g'
+// error-pattern: inline (missed): 'f' not inlined into 'g'
 // dont-check-compiler-stderr
 
 #[no_mangle]
diff --git a/tests/ui/parser/eq-less-to-less-eq.rs b/tests/ui/parser/eq-less-to-less-eq.rs
new file mode 100644
index 00000000000..23c6c59d7a6
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.rs
@@ -0,0 +1,33 @@
+fn foo() {
+    let a = 0;
+    let b = 4;
+    if a =< b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn bar() {
+    let a = 0;
+    let b = 4;
+    if a = <b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn baz() {
+    let a = 0;
+    let b = 4;
+    if a = < b { //~ERROR
+        println!("yay!");
+    }
+}
+
+fn qux() {
+    let a = 0;
+    let b = 4;
+    if a =< i32>::abs(-4) { //~ERROR: mismatched types
+        println!("yay!");
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/parser/eq-less-to-less-eq.stderr b/tests/ui/parser/eq-less-to-less-eq.stderr
new file mode 100644
index 00000000000..4717d8287ff
--- /dev/null
+++ b/tests/ui/parser/eq-less-to-less-eq.stderr
@@ -0,0 +1,34 @@
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:4:15
+   |
+LL |     if a =< b {
+   |          --   ^ expected one of 7 possible tokens
+   |          |
+   |          help: did you mean: `<=`
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:12:15
+   |
+LL |     if a = <b {
+   |               ^ expected one of 7 possible tokens
+
+error: expected one of `!`, `(`, `+`, `::`, `<`, `>`, or `as`, found `{`
+  --> $DIR/eq-less-to-less-eq.rs:20:16
+   |
+LL |     if a = < b {
+   |                ^ expected one of 7 possible tokens
+
+error[E0308]: mismatched types
+  --> $DIR/eq-less-to-less-eq.rs:28:8
+   |
+LL |     if a =< i32>::abs(-4) {
+   |        ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+   |
+help: you might have meant to compare for equality
+   |
+LL |     if a ==< i32>::abs(-4) {
+   |           +
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
new file mode 100644
index 00000000000..d7a418959bf
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs
@@ -0,0 +1,19 @@
+// Tests that dlltool failing to generate an import library will raise an error.
+
+// only-gnu
+// only-windows
+// needs-dlltool
+// compile-flags: --crate-type lib --emit link
+// normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL"
+// normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE"
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    // `@1` is an invalid name to export, as it usually indicates that something
+    // is being exported via ordinal.
+    #[link_name = "@1"]
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
new file mode 100644
index 00000000000..020ac6a2b67
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr
@@ -0,0 +1,5 @@
+error: Dlltool could not create import library: 
+       $DLLTOOL: Syntax error in def file $DEF_FILE:1
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
index 22d57f8bedd..7bc44d65be9 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
 //~^ ERROR import name type must be of the form `import_name_type = "string"`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
index 0e95fec29d2..fb70b987fc7 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: import name type must be of the form `import_name_type = "string"`
-  --> $DIR/import-name-type-invalid-format.rs:5:42
+  --> $DIR/import-name-type-invalid-format.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)]
    |                                          ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
index 7ccb0082fb9..b96f61a26da 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs
@@ -1,8 +1,6 @@
 // ignore-tidy-linelength
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
 //~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
index 7c0e0be911f..9533061892f 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr
@@ -1,5 +1,5 @@
 error: multiple `import_name_type` arguments in a single `#[link]` attribute
-  --> $DIR/import-name-type-multiple.rs:6:74
+  --> $DIR/import-name-type-multiple.rs:4:74
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")]
    |                                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
index f728a578d3b..067e82a17fd 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
 //~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
index 2b299f2fea3..2bce9758e99 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr
@@ -1,5 +1,5 @@
 error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated
-  --> $DIR/import-name-type-unknown-value.rs:5:42
+  --> $DIR/import-name-type-unknown-value.rs:3:42
    |
 LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")]
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
index ae9207864a2..34e907bde83 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs
@@ -1,7 +1,5 @@
 // only-windows
 // only-x86
-#![feature(raw_dylib)]
-
 #[link(name = "foo", import_name_type = "decorated")]
 //~^ ERROR import name type can only be used with link kind `raw-dylib`
 extern "C" { }
diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
index 5898cd875a1..75cadc471c4 100644
--- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:5:22
+  --> $DIR/import-name-type-unsupported-link-kind.rs:3:22
    |
 LL | #[link(name = "foo", import_name_type = "decorated")]
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: import name type can only be used with link kind `raw-dylib`
-  --> $DIR/import-name-type-unsupported-link-kind.rs:9:39
+  --> $DIR/import-name-type-unsupported-link-kind.rs:7:39
    |
 LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")]
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
new file mode 100644
index 00000000000..a07be9d92b4
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs
@@ -0,0 +1,13 @@
+// Tests that failing to run dlltool will raise an error.
+
+// only-gnu
+// only-windows
+// compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe
+#[link(name = "foo", kind = "raw-dylib")]
+extern "C" {
+    fn f(x: i32);
+}
+
+pub fn lib_main() {
+    unsafe { f(42); }
+}
diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
new file mode 100644
index 00000000000..3ae901e0dbc
--- /dev/null
+++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr
@@ -0,0 +1,4 @@
+error: Error calling dlltool 'does_not_exit.exe': program not found
+
+error: aborting due to previous error
+
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
index 1a128c87a0c..b04c2facbcd 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name="foo")]
 extern "C" {
     #[link_name="foo"]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
index 481a06d2797..f1e54d37827 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
@@ -1,11 +1,11 @@
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:6:5
+  --> $DIR/link-ordinal-and-name.rs:4:5
    |
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: cannot use `#[link_name]` with `#[link_ordinal]`
-  --> $DIR/link-ordinal-and-name.rs:10:5
+  --> $DIR/link-ordinal-and-name.rs:8:5
    |
 LL |     #[link_ordinal(5)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
index 7c8da050cf6..9b7e8d70743 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal("JustMonika")]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
index 55cdcad75a4..6341e57a0be 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
@@ -1,5 +1,5 @@
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:5:5
+  --> $DIR/link-ordinal-invalid-format.rs:3:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal("JustMonika")]
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
 error: illegal ordinal format in `link_ordinal`
-  --> $DIR/link-ordinal-invalid-format.rs:8:5
+  --> $DIR/link-ordinal-invalid-format.rs:6:5
    |
 LL |     #[link_ordinal("JustMonika")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
index 9feed394110..6b8cd49566d 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal()]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
index 853cdad8c1c..1b04bb228e7 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:5:5
+  --> $DIR/link-ordinal-missing-argument.rs:3:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal()]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-missing-argument.rs:8:5
+  --> $DIR/link-ordinal-missing-argument.rs:6:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
index 631c363d4ba..8842cb94404 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
@@ -1,6 +1,4 @@
 // only-windows
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
index c0453d2bf01..2e6cf3761c2 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
@@ -1,23 +1,23 @@
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:6:5
+  --> $DIR/link-ordinal-multiple.rs:4:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:7:5
+  --> $DIR/link-ordinal-multiple.rs:5:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: multiple `link_ordinal` attributes
-  --> $DIR/link-ordinal-multiple.rs:9:5
+  --> $DIR/link-ordinal-multiple.rs:7:5
    |
 LL |     #[link_ordinal(1)]
    |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/link-ordinal-multiple.rs:10:5
+  --> $DIR/link-ordinal-multiple.rs:8:5
    |
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
index 54e614164b3..f33a3d62e26 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link_ordinal(123)]
 //~^ ERROR attribute should be applied to a foreign function or static
 struct Foo {}
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
index ec4104fbe50..8f279508720 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
@@ -1,17 +1,17 @@
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:3:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:1:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:7:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:5:1
    |
 LL | #[link_ordinal(123)]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a foreign function or static
-  --> $DIR/link-ordinal-not-foreign-fn.rs:11:1
+  --> $DIR/link-ordinal-not-foreign-fn.rs:9:1
    |
 LL | #[link_ordinal(42)]
    | ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
index 46731581ebc..9d741630fc9 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(72436)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
index fef6de6aedf..811145e77ee 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
@@ -1,5 +1,5 @@
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:5:5
+  --> $DIR/link-ordinal-too-large.rs:3:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(72436)]
    = note: the value may not exceed `u16::MAX`
 
 error: ordinal value in `link_ordinal` is too large: `72436`
-  --> $DIR/link-ordinal-too-large.rs:8:5
+  --> $DIR/link-ordinal-too-large.rs:6:5
    |
 LL |     #[link_ordinal(72436)]
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
index 71e0ac9f3ee..9988115fd8b 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3, 4)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
index 7e0fcd845cb..d5ce8aff34f 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
@@ -1,5 +1,5 @@
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:5:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:3:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[link_ordinal(3, 4)]
    = note: the attribute requires exactly one argument
 
 error: incorrect number of arguments to `#[link_ordinal]`
-  --> $DIR/link-ordinal-too-many-arguments.rs:8:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:6:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
index 329c93fc196..14e915d602a 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
-
 #[link(name = "foo")]
 extern "C" {
     #[link_ordinal(3)]
diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
index 5fbffbda570..200b8f62874 100644
--- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
@@ -1,11 +1,11 @@
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:5:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:3:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
 
 error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-  --> $DIR/link-ordinal-unsupported-link-kind.rs:12:5
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:10:5
    |
 LL |     #[link_ordinal(3)]
    |     ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
index 6542faad264..b4173f3b60b 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs
@@ -2,7 +2,6 @@
 // only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
-#![feature(raw_dylib)]
 #[link(name = "foo", kind = "raw-dylib")]
 extern "C" {
     fn f(x: i32);
diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
index c6808bec7b5..51010840548 100644
--- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -1,5 +1,5 @@
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:14:9
+  --> $DIR/multiple-declarations.rs:13:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
index 4efffbd532e..d4c6658a330 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs
@@ -1,6 +1,5 @@
 // ignore-windows
 // compile-flags: --crate-type lib
-#![cfg_attr(target_arch = "x86", feature(raw_dylib))]
 #[link(name = "foo", kind = "raw-dylib")]
 //~^ ERROR: link kind `raw-dylib` is only supported on Windows targets
 extern "C" {}
diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
index 14e791f1fb9..b635a09afba 100644
--- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
+++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr
@@ -1,5 +1,5 @@
 error[E0455]: link kind `raw-dylib` is only supported on Windows targets
-  --> $DIR/raw-dylib-windows-only.rs:4:29
+  --> $DIR/raw-dylib-windows-only.rs:3:29
    |
 LL | #[link(name = "foo", kind = "raw-dylib")]
    |                             ^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
new file mode 100644
index 00000000000..e4b07ab8108
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/basic.rs
@@ -0,0 +1,7 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(b"test\0", c"test".to_bytes_with_nul());
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
new file mode 100644
index 00000000000..b27da26ed23
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.rs
@@ -0,0 +1,13 @@
+// gate-test-c_str_literals
+
+macro_rules! m {
+    ($t:tt) => {}
+}
+
+fn main() {
+    c"foo";
+    //~^ ERROR: `c".."` literals are experimental
+
+    m!(c"test");
+    //~^ ERROR: `c".."` literals are experimental
+}
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
new file mode 100644
index 00000000000..bc0c537aada
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/gate.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:8:5
+   |
+LL |     c"foo";
+   |     ^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error[E0658]: `c".."` literals are experimental
+  --> $DIR/gate.rs:11:8
+   |
+LL |     m!(c"test");
+   |        ^^^^^^^
+   |
+   = note: see issue #105723 <https://github.com/rust-lang/rust/issues/105723> for more information
+   = help: add `#![feature(c_str_literals)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs
new file mode 100644
index 00000000000..7bc6097f124
Binary files /dev/null and b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.rs differ
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr
new file mode 100644
index 00000000000..ff9006f6f97
Binary files /dev/null and b/tests/ui/rfcs/rfc-3348-c-string-literals/no-nuls.stderr differ
diff --git a/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
new file mode 100644
index 00000000000..82e8e2090d7
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3348-c-string-literals/non-ascii.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+#![feature(c_str_literals)]
+
+fn main() {
+    assert_eq!(
+        c"\xEF\x80🦀\u{1F980}".to_bytes_with_nul(),
+        &[0xEF, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0xF0, 0x9F, 0xA6, 0x80, 0x00],
+    );
+}
diff --git a/tests/ui/simd/issue-105439.rs b/tests/ui/simd/issue-105439.rs
new file mode 100644
index 00000000000..35ca76e989b
--- /dev/null
+++ b/tests/ui/simd/issue-105439.rs
@@ -0,0 +1,25 @@
+// run-pass
+// compile-flags: -O -Zverify-llvm-ir
+
+#![feature(repr_simd)]
+#![feature(platform_intrinsics)]
+
+#[allow(non_camel_case_types)]
+#[derive(Clone, Copy)]
+#[repr(simd)]
+struct i32x4([i32; 4]);
+
+extern "platform-intrinsic" {
+    pub(crate) fn simd_add<T>(x: T, y: T) -> T;
+}
+
+#[inline(always)]
+fn to_array(a: i32x4) -> [i32; 4] {
+    a.0
+}
+
+fn main() {
+    let a = i32x4([1, 2, 3, 4]);
+    let b = unsafe { simd_add(a, a) };
+    assert_eq!(to_array(b), [2, 4, 6, 8]);
+}
diff --git a/tests/ui/specialization/issue-111232.rs b/tests/ui/specialization/issue-111232.rs
new file mode 100644
index 00000000000..3ed3c580e6d
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.rs
@@ -0,0 +1,11 @@
+#![feature(min_specialization)]
+
+struct S;
+
+impl From<S> for S {
+    fn from(s: S) -> S { //~ ERROR `from` specializes an item from a parent `impl`, but that item is not marked `default`
+        s
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/specialization/issue-111232.stderr b/tests/ui/specialization/issue-111232.stderr
new file mode 100644
index 00000000000..27ee42fc00c
--- /dev/null
+++ b/tests/ui/specialization/issue-111232.stderr
@@ -0,0 +1,11 @@
+error[E0520]: `from` specializes an item from a parent `impl`, but that item is not marked `default`
+  --> $DIR/issue-111232.rs:6:5
+   |
+LL |     fn from(s: S) -> S {
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: parent implementation is in crate `core`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0520`.
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr
new file mode 100644
index 00000000000..a985b1a6e12
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.no.stderr
@@ -0,0 +1,24 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/drop-impl-pred.rs:6:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0367]: `Drop` impl requires `H: Foo` but the struct it is implemented for does not
+  --> $DIR/drop-impl-pred.rs:19:15
+   |
+LL |     for<H> H: Foo,
+   |               ^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/drop-impl-pred.rs:12:1
+   |
+LL | struct Bar<T>(T) where T: Foo;
+   | ^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0367`.
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs
new file mode 100644
index 00000000000..c65b5ea9ba4
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.rs
@@ -0,0 +1,25 @@
+// revisions: no yes
+//[yes] check-pass
+
+// Issue 110557
+
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+pub trait Foo {}
+
+#[cfg(no)]
+struct Bar<T>(T) where T: Foo;
+
+#[cfg(yes)]
+struct Bar<T>(T) where for<H> H: Foo;
+
+impl<T> Drop for Bar<T>
+where
+    for<H> H: Foo,
+//[no]~^ ERROR `Drop` impl requires `H: Foo` but the struct it is implemented for does not
+{
+    fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr
new file mode 100644
index 00000000000..165cf2ee13d
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/drop-impl-pred.yes.stderr
@@ -0,0 +1,11 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/drop-impl-pred.rs:6:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/x b/x
index 4309b82627c..d967988e1c4 100755
--- a/x
+++ b/x
@@ -7,9 +7,12 @@
 
 set -eu
 
+# syntax check
+sh -n $0
+
 realpath() {
     if [ -d "$1" ]; then
-        CDPATH='' command cd "$1" && pwd -P   
+        CDPATH='' command cd "$1" && pwd -P
     else
         echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
     fi
diff --git a/x.ps1 b/x.ps1
index b0cddc9f930..a156017628d 100755
--- a/x.ps1
+++ b/x.ps1
@@ -2,6 +2,11 @@
 
 # See ./x for why these scripts exist.
 
+$ErrorActionPreference = "Stop"
+
+# syntax check
+Get-Command -syntax ${PSCommandPath}
+
 $xpy = Join-Path $PSScriptRoot x.py
 # Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
 # Double-quote all the arguments so it doesn't do that.