diff --git a/Cargo.lock b/Cargo.lock
index 96d9449db57c0..f51712e8e2cc2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3595,6 +3595,7 @@ dependencies = [
  "rustc_index",
  "rustc_infer",
  "rustc_lexer",
+ "rustc_macros",
  "rustc_middle",
  "rustc_mir_dataflow",
  "rustc_serialize",
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
index 0b531623ba6f5..8a35921d745cf 100644
--- a/compiler/rustc_borrowck/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -19,6 +19,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_lexer = { path = "../rustc_lexer" }
+rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_const_eval = { path = "../rustc_const_eval" }
 rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 07f182102f346..1ef2b0ae98843 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -19,6 +19,9 @@ use std::fmt;
 use std::rc::Rc;
 
 use crate::region_infer::values::RegionElement;
+use crate::session_diagnostics::HigherRankedErrorCause;
+use crate::session_diagnostics::HigherRankedLifetimeError;
+use crate::session_diagnostics::HigherRankedSubtypeError;
 use crate::MirBorrowckCtxt;
 
 #[derive(Clone)]
@@ -69,7 +72,7 @@ impl<'tcx> UniverseInfo<'tcx> {
                 // up in the existing UI tests. Consider investigating this
                 // some more.
                 mbcx.buffer_error(
-                    mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
+                    mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
                 );
             }
         }
@@ -216,9 +219,12 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
         tcx: TyCtxt<'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
-        err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
-        err
+        tcx.sess.create_err(HigherRankedLifetimeError {
+            cause: Some(HigherRankedErrorCause::CouldNotProve {
+                predicate: self.canonical_query.value.value.predicate.to_string(),
+            }),
+            span,
+        })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
@@ -263,9 +269,12 @@ where
         tcx: TyCtxt<'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
-        err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
-        err
+        tcx.sess.create_err(HigherRankedLifetimeError {
+            cause: Some(HigherRankedErrorCause::CouldNotNormalize {
+                value: self.canonical_query.value.value.value.to_string(),
+            }),
+            span,
+        })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
@@ -326,7 +335,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
         // and is only the fallback when the nice error fails. Consider improving this some more.
-        tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
+        tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
@@ -366,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
         // and is only the fallback when the nice error fails. Consider improving this some more.
-        tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
+        tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index e0f8da1c872d3..5d3997289bb33 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -24,6 +24,7 @@ use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 use crate::borrowck_errors;
+use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
 
 use super::{OutlivesSuggestionBuilder, RegionName};
 use crate::region_infer::BlameConstraint;
@@ -196,9 +197,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         // to report it; we could probably handle it by
                         // iterating over the universal regions and reporting
                         // an error that multiple bounds are required.
-                        self.buffer_error(self.infcx.tcx.sess.struct_span_err(
-                            type_test_span,
-                            &format!("`{}` does not live long enough", type_test.generic_kind),
+                        self.buffer_error(self.infcx.tcx.sess.create_err(
+                            GenericDoesNotLiveLongEnough {
+                                kind: type_test.generic_kind.to_string(),
+                                span: type_test_span,
+                            },
                         ));
                     }
                 }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a2df072aa3119..7d6f37340c2bb 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -76,6 +76,7 @@ mod places_conflict;
 mod prefixes;
 mod region_infer;
 mod renumber;
+mod session_diagnostics;
 mod type_check;
 mod universal_regions;
 mod used_muts;
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
new file mode 100644
index 0000000000000..895723d44ff1b
--- /dev/null
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -0,0 +1,44 @@
+use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_middle::ty::Ty;
+use rustc_span::Span;
+
+#[derive(SessionDiagnostic)]
+#[error(borrowck::move_unsized, code = "E0161")]
+pub(crate) struct MoveUnsized<'tcx> {
+    pub ty: Ty<'tcx>,
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(borrowck::higher_ranked_lifetime_error)]
+pub(crate) struct HigherRankedLifetimeError {
+    #[subdiagnostic]
+    pub cause: Option<HigherRankedErrorCause>,
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum HigherRankedErrorCause {
+    #[note(borrowck::could_not_prove)]
+    CouldNotProve { predicate: String },
+    #[note(borrowck::could_not_normalize)]
+    CouldNotNormalize { value: String },
+}
+
+#[derive(SessionDiagnostic)]
+#[error(borrowck::higher_ranked_subtype_error)]
+pub(crate) struct HigherRankedSubtypeError {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(borrowck::generic_does_not_live_long_enough)]
+pub(crate) struct GenericDoesNotLiveLongEnough {
+    pub kind: String,
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 542fc6b0f485d..5ee1f5a8e8e37 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -9,7 +9,6 @@ use hir::OpaqueTyOrigin;
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
@@ -48,6 +47,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
 
+use crate::session_diagnostics::MoveUnsized;
 use crate::{
     borrow_set::BorrowSet,
     constraints::{OutlivesConstraint, OutlivesConstraintSet},
@@ -1780,19 +1780,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // slot or local, so to find all unsized rvalues it is enough
             // to check all temps, return slots and locals.
             if self.reported_errors.replace((ty, span)).is_none() {
-                let mut diag = struct_span_err!(
-                    self.tcx().sess,
-                    span,
-                    E0161,
-                    "cannot move a value of type {0}: the size of {0} \
-                     cannot be statically determined",
-                    ty
-                );
-
                 // While this is located in `nll::typeck` this error is not
                 // an NLL error, it's a required check to prevent creation
                 // of unsized rvalues in a call expression.
-                diag.emit();
+                self.tcx().sess.emit_err(MoveUnsized { ty, span });
             }
         }
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 71699b5cf3830..551733e7abe93 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -103,14 +103,14 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
             // for macOS to understand. For more info see #11352
             // This can be overridden using --llvm-opts -dwarf-version,N.
             // Android has the same issue (#22398)
-            if let Some(version) = sess.target.dwarf_version {
-                llvm::LLVMRustAddModuleFlag(
-                    self.llmod,
-                    llvm::LLVMModFlagBehavior::Warning,
-                    "Dwarf Version\0".as_ptr().cast(),
-                    version,
-                )
-            }
+            let dwarf_version =
+                sess.opts.debugging_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
+            llvm::LLVMRustAddModuleFlag(
+                self.llmod,
+                llvm::LLVMModFlagBehavior::Warning,
+                "Dwarf Version\0".as_ptr().cast(),
+                dwarf_version,
+            );
 
             // Indicate that we want CodeView debug information on MSVC
             if sess.target.is_like_msvc {
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index fb484fba9fd06..076415b2d1b2f 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -366,22 +366,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
             (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                 assert_eq!(def_a, def_b);
-                if def_a.is_box() || def_b.is_box() {
-                    if !def_a.is_box() || !def_b.is_box() {
-                        span_bug!(
-                            self.cur_span(),
-                            "invalid unsizing between {:?} -> {:?}",
-                            src.layout.ty,
-                            cast_ty.ty
-                        );
-                    }
-                    return self.unsize_into_ptr(
-                        src,
-                        dest,
-                        src.layout.ty.boxed_ty(),
-                        cast_ty.ty.boxed_ty(),
-                    );
-                }
 
                 // unsizing of generic struct with pointer fields
                 // Example: `Arc<T>` -> `Arc<Trait>`
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 630281bb09254..905ab6cb578fc 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -594,7 +594,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 Ok(true)
             }
             ty::Adt(def, ..) if def.is_box() => {
-                self.check_safe_pointer(value, "box")?;
+                let unique = self.ecx.operand_field(value, 0)?;
+                let nonnull = self.ecx.operand_field(&unique, 0)?;
+                let ptr = self.ecx.operand_field(&nonnull, 0)?;
+                self.check_safe_pointer(&ptr, "box")?;
+
+                // Check other fields of Box
+                self.walk_value(value)?;
                 Ok(true)
             }
             ty::FnPtr(_sig) => {
diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
new file mode 100644
index 0000000000000..645673ef47aeb
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
@@ -0,0 +1,18 @@
+borrowck-move-unsized =
+    cannot move a value of type `{$ty}`
+    .label = the size of `{$ty}` cannot be statically determined
+
+borrowck-higher-ranked-lifetime-error =
+    higher-ranked lifetime error
+
+borrowck-could-not-prove =
+    could not prove `{$predicate}`
+
+borrowck-could-not-normalize =
+    could not normalize `{$value}`
+
+borrowck-higher-ranked-subtype-error =
+    higher-ranked subtype error
+  
+generic-does-not-live-long-enough =
+    `{$kind}` does not live long enough
\ No newline at end of file
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 90eb5ef54462d..d52b94b78dfac 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -35,6 +35,7 @@ fluent_messages! {
     privacy => "../locales/en-US/privacy.ftl",
     typeck => "../locales/en-US/typeck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
+    borrowck => "../locales/en-US/borrowck.ftl",
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 8b2a995f1c58e..6d74e9a9f2b9e 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -281,9 +281,19 @@ pub trait Emitter {
         let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle");
         let value = match attr {
             Some(attr) => {
-                message.get_attribute(attr).expect("missing attribute in fluent message").value()
+                if let Some(attr) = message.get_attribute(attr) {
+                    attr.value()
+                } else {
+                    panic!("missing attribute `{attr}` in fluent message `{identifier}`")
+                }
+            }
+            None => {
+                if let Some(value) = message.value() {
+                    value
+                } else {
+                    panic!("missing value in fluent message `{identifier}`")
+                }
             }
-            None => message.value().expect("missing value in fluent message"),
         };
 
         let mut err = vec![];
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 502afa493fe66..5b263aded9cdf 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -972,6 +972,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             if !tcx.sess.opts.debugging_opts.thir_unsafeck {
                 rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
             }
+            tcx.ensure().has_ffi_unwind_calls(def_id);
 
             if tcx.hir().body_const_context(def_id).is_some() {
                 tcx.ensure()
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 30a29ed6ed38f..b3dbbfe7fc7ad 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -733,6 +733,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(dep_info_omit_d_target, true);
     tracked!(drop_tracking, true);
     tracked!(dual_proc_macros, true);
+    tracked!(dwarf_version, Some(5));
     tracked!(fewer_names, Some(true));
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index d52455e2576c9..40601bb5aad47 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3231,6 +3231,7 @@ declare_lint_pass! {
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         TEST_UNSTABLE_LINT,
+        FFI_UNWIND_CALLS,
     ]
 }
 
@@ -3896,3 +3897,42 @@ declare_lint! {
     "this unstable lint is only for testing",
     @feature_gate = sym::test_unstable_lint;
 }
+
+declare_lint! {
+    /// The `ffi_unwind_calls` lint detects calls to foreign functions or function pointers with
+    /// `C-unwind` or other FFI-unwind ABIs.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (need FFI)
+    /// #![feature(ffi_unwind_calls)]
+    /// #![feature(c_unwind)]
+    ///
+    /// # mod impl {
+    /// #     #[no_mangle]
+    /// #     pub fn "C-unwind" fn foo() {}
+    /// # }
+    ///
+    /// extern "C-unwind" {
+    ///     fn foo();
+    /// }
+    ///
+    /// fn bar() {
+    ///     unsafe { foo(); }
+    ///     let ptr: unsafe extern "C-unwind" fn() = foo;
+    ///     unsafe { ptr(); }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// For crates containing such calls, if they are compiled with `-C panic=unwind` then the
+    /// produced library cannot be linked with crates compiled with `-C panic=abort`. For crates
+    /// that desire this ability it is therefore necessary to avoid such calls.
+    pub FFI_UNWIND_CALLS,
+    Allow,
+    "call to foreign functions or function pointers with FFI-unwind ABI",
+    @feature_gate = sym::c_unwind;
+}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 555db5846edd0..cb50c0fb7385f 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -748,7 +748,7 @@ impl<'a> CrateLoader<'a> {
         if !data.is_panic_runtime() {
             self.sess.err(&format!("the crate `{}` is not a panic runtime", name));
         }
-        if data.panic_strategy() != desired_strategy {
+        if data.required_panic_strategy() != Some(desired_strategy) {
             self.sess.err(&format!(
                 "the crate `{}` does not have the panic \
                                     strategy `{}`",
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 245b2076ebca9..770d164894a73 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -60,7 +60,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
-use rustc_target::spec::PanicStrategy;
 
 pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.sess
@@ -367,14 +366,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                     prev_name, cur_name
                 ));
             }
-            panic_runtime = Some((cnum, tcx.panic_strategy(cnum)));
+            panic_runtime = Some((
+                cnum,
+                tcx.required_panic_strategy(cnum).unwrap_or_else(|| {
+                    bug!("cannot determine panic strategy of a panic runtime");
+                }),
+            ));
         }
     }
 
     // If we found a panic runtime, then we know by this point that it's the
     // only one, but we perform validation here that all the panic strategy
     // compilation modes for the whole DAG are valid.
-    if let Some((cnum, found_strategy)) = panic_runtime {
+    if let Some((runtime_cnum, found_strategy)) = panic_runtime {
         let desired_strategy = sess.panic_strategy();
 
         // First up, validate that our selected panic runtime is indeed exactly
@@ -384,7 +388,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                 "the linked panic runtime `{}` is \
                                not compiled with this crate's \
                                panic strategy `{}`",
-                tcx.crate_name(cnum),
+                tcx.crate_name(runtime_cnum),
                 desired_strategy.desc()
             ));
         }
@@ -397,18 +401,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             if let Linkage::NotLinked = *linkage {
                 continue;
             }
-            if desired_strategy == PanicStrategy::Abort {
-                continue;
-            }
             let cnum = CrateNum::new(i + 1);
-            if tcx.is_compiler_builtins(cnum) {
+            if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
                 continue;
             }
 
-            let found_strategy = tcx.panic_strategy(cnum);
-            if desired_strategy != found_strategy {
+            if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy {
                 sess.err(&format!(
-                    "the crate `{}` is compiled with the \
+                    "the crate `{}` requires \
                                panic strategy `{}` which is \
                                incompatible with this crate's \
                                strategy of `{}`",
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3280fd5c3108b..f0ccf02c9fa5f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1758,8 +1758,8 @@ impl CrateMetadata {
         self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
     }
 
-    pub(crate) fn panic_strategy(&self) -> PanicStrategy {
-        self.root.panic_strategy
+    pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> {
+        self.root.required_panic_strategy
     }
 
     pub(crate) fn needs_panic_runtime(&self) -> bool {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 0bea2a10da896..565eec18ea9b8 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -246,7 +246,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     has_global_allocator => { cdata.root.has_global_allocator }
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
-    panic_strategy => { cdata.root.panic_strategy }
+    required_panic_strategy => { cdata.root.required_panic_strategy }
     panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
     extern_crate => {
         let r = *cdata.extern_crate.lock();
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 75286b8906871..bb4b502bded45 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -665,7 +665,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             triple: tcx.sess.opts.target_triple.clone(),
             hash: tcx.crate_hash(LOCAL_CRATE),
             stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
-            panic_strategy: tcx.sess.panic_strategy(),
+            required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
             panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop,
             edition: tcx.sess.edition(),
             has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a58c0e68ee38c..a50eb2a71cf4a 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -217,7 +217,7 @@ pub(crate) struct CrateRoot {
     extra_filename: String,
     hash: Svh,
     stable_crate_id: StableCrateId,
-    panic_strategy: PanicStrategy,
+    required_panic_strategy: Option<PanicStrategy>,
     panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 2e68fc8a7c050..095e8cbdd10a0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1358,9 +1358,13 @@ rustc_queries! {
         desc { "query a crate is `#![profiler_runtime]`" }
         separate_provide_extern
     }
-    query panic_strategy(_: CrateNum) -> PanicStrategy {
+    query has_ffi_unwind_calls(key: LocalDefId) -> bool {
+        desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+        cache_on_disk_if { true }
+    }
+    query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
         fatal_cycle
-        desc { "query a crate's configured panic strategy" }
+        desc { "query a crate's required panic strategy" }
         separate_provide_extern
     }
     query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index 11980382ffdb2..2c8389e532dd7 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,6 +1,5 @@
 use crate::MirPass;
 use rustc_ast::InlineAsmOptions;
-use rustc_hir::def::DefKind;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
@@ -31,11 +30,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
 
         // We don't simplify the MIR of constants at this time because that
         // namely results in a cyclic query when we call `tcx.type_of` below.
-        let is_function = match kind {
-            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
-            _ => tcx.is_closure(def_id),
-        };
-        if !is_function {
+        if !kind.is_fn_like() {
             return;
         }
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
new file mode 100644
index 0000000000000..7728fdaffb0dc
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -0,0 +1,170 @@
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
+use rustc_middle::mir::*;
+use rustc_middle::ty::layout;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
+use rustc_target::spec::abi::Abi;
+use rustc_target::spec::PanicStrategy;
+
+fn abi_can_unwind(abi: Abi) -> bool {
+    use Abi::*;
+    match abi {
+        C { unwind }
+        | System { unwind }
+        | Cdecl { unwind }
+        | Stdcall { unwind }
+        | Fastcall { unwind }
+        | Vectorcall { unwind }
+        | Thiscall { unwind }
+        | Aapcs { unwind }
+        | Win64 { unwind }
+        | SysV64 { unwind } => unwind,
+        PtxKernel
+        | Msp430Interrupt
+        | X86Interrupt
+        | AmdGpuKernel
+        | EfiApi
+        | AvrInterrupt
+        | AvrNonBlockingInterrupt
+        | CCmseNonSecureCall
+        | Wasm
+        | RustIntrinsic
+        | PlatformIntrinsic
+        | Unadjusted => false,
+        Rust | RustCall | RustCold => true,
+    }
+}
+
+// Check if the body of this def_id can possibly leak a foreign unwind into Rust code.
+fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
+    debug!("has_ffi_unwind_calls({local_def_id:?})");
+
+    // Only perform check on functions because constants cannot call FFI functions.
+    let def_id = local_def_id.to_def_id();
+    let kind = tcx.def_kind(def_id);
+    if !kind.is_fn_like() {
+        return false;
+    }
+
+    let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow();
+
+    let body_ty = tcx.type_of(def_id);
+    let body_abi = match body_ty.kind() {
+        ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
+        ty::Closure(..) => Abi::RustCall,
+        ty::Generator(..) => Abi::Rust,
+        _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
+    };
+    let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi);
+
+    // Foreign unwinds cannot leak past functions that themselves cannot unwind.
+    if !body_can_unwind {
+        return false;
+    }
+
+    let mut tainted = false;
+
+    for block in body.basic_blocks() {
+        if block.is_cleanup {
+            continue;
+        }
+        let Some(terminator) = &block.terminator else { continue };
+        let TerminatorKind::Call { func, .. } = &terminator.kind else { continue };
+
+        let ty = func.ty(body, tcx);
+        let sig = ty.fn_sig(tcx);
+
+        // Rust calls cannot themselves create foreign unwinds.
+        if let Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() {
+            continue;
+        };
+
+        let fn_def_id = match ty.kind() {
+            ty::FnPtr(_) => None,
+            &ty::FnDef(def_id, _) => {
+                // Rust calls cannot themselves create foreign unwinds.
+                if !tcx.is_foreign_item(def_id) {
+                    continue;
+                }
+                Some(def_id)
+            }
+            _ => bug!("invalid callee of type {:?}", ty),
+        };
+
+        if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) {
+            // We have detected a call that can possibly leak foreign unwind.
+            //
+            // Because the function body itself can unwind, we are not aborting this function call
+            // upon unwind, so this call can possibly leak foreign unwind into Rust code if the
+            // panic runtime linked is panic-abort.
+
+            let lint_root = body.source_scopes[terminator.source_info.scope]
+                .local_data
+                .as_ref()
+                .assert_crate_local()
+                .lint_root;
+            let span = terminator.source_info.span;
+
+            tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| {
+                let msg = match fn_def_id {
+                    Some(_) => "call to foreign function with FFI-unwind ABI",
+                    None => "call to function pointer with FFI-unwind ABI",
+                };
+                let mut db = lint.build(msg);
+                db.span_label(span, msg);
+                db.emit();
+            });
+
+            tainted = true;
+        }
+    }
+
+    tainted
+}
+
+fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> {
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    if tcx.is_panic_runtime(LOCAL_CRATE) {
+        return Some(tcx.sess.panic_strategy());
+    }
+
+    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
+        return Some(PanicStrategy::Abort);
+    }
+
+    for def_id in tcx.hir().body_owners() {
+        if tcx.has_ffi_unwind_calls(def_id) {
+            // Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls`
+            // MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception
+            // can enter Rust through these sites.
+            //
+            // On the other hand, crates compiled with `-C panic=abort` expects that all Rust
+            // functions cannot unwind (whether it's caused by Rust panic or foreign exception),
+            // and this expectation mismatch can cause unsoundness (#96926).
+            //
+            // To address this issue, we enforce that if FFI-unwind calls are used in a crate
+            // compiled with `panic=unwind`, then the final panic strategy must be `panic=unwind`.
+            // This will ensure that no crates will have wrong unwindability assumption.
+            //
+            // It should be noted that it is okay to link `panic=unwind` into a `panic=abort`
+            // program if it contains no FFI-unwind calls. In such case foreign exception can only
+            // enter Rust in a `panic=abort` crate, which will lead to an abort. There will also
+            // be no exceptions generated from Rust, so the assumption which `panic=abort` crates
+            // make, that no Rust function can unwind, indeed holds for crates compiled with
+            // `panic=unwind` as well. In such case this function returns `None`, indicating that
+            // the crate does not require a particular final panic strategy, and can be freely
+            // linked to crates with either strategy (we need such ability for libstd and its
+            // dependencies).
+            return Some(PanicStrategy::Unwind);
+        }
+    }
+
+    // This crate can be linked with either runtime.
+    None
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+    *providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers };
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b7caa61ef07a7..12fcb299ce3f4 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -59,6 +59,7 @@ pub mod dump_mir;
 mod early_otherwise_branch;
 mod elaborate_box_derefs;
 mod elaborate_drops;
+mod ffi_unwind_calls;
 mod function_item_references;
 mod generator;
 mod inline;
@@ -98,6 +99,7 @@ pub fn provide(providers: &mut Providers) {
     check_unsafety::provide(providers);
     check_packed_ref::provide(providers);
     coverage::query::provide(providers);
+    ffi_unwind_calls::provide(providers);
     shim::provide(providers);
     *providers = Providers {
         mir_keys,
@@ -223,6 +225,9 @@ fn mir_const<'tcx>(
         }
     }
 
+    // has_ffi_unwind_calls query uses the raw mir, so make sure it is run.
+    tcx.ensure().has_ffi_unwind_calls(def.did);
+
     let mut body = tcx.mir_built(def).steal();
 
     rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 441e1f9f6a2b8..372402c80096a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1269,6 +1269,8 @@ options! {
         computed `block` spans (one span encompassing a block's terminator and \
         all statements). If `-Z instrument-coverage` is also enabled, create \
         an additional `.html` file showing the computed coverage spans."),
+    dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
+        "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index b5058fd699aca..d3beb123ad1a6 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1489,6 +1489,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             ))
         }
     }
+
+    if let Some(dwarf_version) = sess.opts.debugging_opts.dwarf_version {
+        if dwarf_version > 5 {
+            sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
+        }
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index c2b9d696776f5..dc06597db6fd4 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -3,7 +3,7 @@ use crate::spec::TargetOptions;
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
     base.os = "android".into();
-    base.dwarf_version = Some(2);
+    base.default_dwarf_version = 2;
     base.position_independent_executables = true;
     base.has_thread_local = false;
     // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e8460a509e2ba..713dc9a1f0ea7 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -28,7 +28,7 @@ pub fn opts(os: &'static str) -> TargetOptions {
         executables: true,
         families: cvs!["unix"],
         is_like_osx: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         frame_pointer: FramePointer::Always,
         has_rpath: true,
         dll_suffix: ".dylib".into(),
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index b59322d07f57a..c1e469746cb4c 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index a7e0f9f704127..36312d26e3700 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -10,7 +10,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index a08603da04095..48ccb10f21426 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1275,9 +1275,9 @@ pub struct TargetOptions {
     pub is_like_msvc: bool,
     /// Whether a target toolchain is like WASM.
     pub is_like_wasm: bool,
-    /// Version of DWARF to use if not using the default.
+    /// Default supported version of DWARF on this platform.
     /// Useful because some platforms (osx, bsd) only want up to DWARF2.
-    pub dwarf_version: Option<u32>,
+    pub default_dwarf_version: u32,
     /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
@@ -1539,7 +1539,7 @@ impl Default for TargetOptions {
             is_like_windows: false,
             is_like_msvc: false,
             is_like_wasm: false,
-            dwarf_version: None,
+            default_dwarf_version: 4,
             linker_is_gnu: true,
             allows_weak_linkage: true,
             has_rpath: false,
@@ -1778,13 +1778,13 @@ impl Target {
                     base.$key_name = s;
                 }
             } );
-            ($key_name:ident, Option<u32>) => ( {
+            ($key_name:ident, u32) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".into());
                     }
-                    base.$key_name = Some(s as u32);
+                    base.$key_name = s as u32;
                 }
             } );
             ($key_name:ident, Option<u64>) => ( {
@@ -2143,7 +2143,7 @@ impl Target {
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
         key!(is_like_wasm, bool);
-        key!(dwarf_version, Option<u32>);
+        key!(default_dwarf_version, u32);
         key!(linker_is_gnu, bool);
         key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
@@ -2387,7 +2387,7 @@ impl ToJson for Target {
         target_option_val!(is_like_windows);
         target_option_val!(is_like_msvc);
         target_option_val!(is_like_wasm);
-        target_option_val!(dwarf_version);
+        target_option_val!(default_dwarf_version);
         target_option_val!(linker_is_gnu);
         target_option_val!(allows_weak_linkage);
         target_option_val!(has_rpath);
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 69016d77cf97b..40ef04ba04382 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -11,7 +11,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         use_ctors_section: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index bbd322bb6ce2b..51cecdd47eab2 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -11,7 +11,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 5d08ea99ac64a..424eff2f6212a 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -236,7 +236,7 @@ impl<'tcx> AbstractConst<'tcx> {
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
         let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
         debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
-        Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs }))
+        Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
     }
 
     pub fn from_const(
@@ -416,6 +416,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                     // `AbstractConst`s should not contain any promoteds as they require references which
                     // are not allowed.
                     assert_eq!(ct.promoted, None);
+                    assert_eq!(ct, self.tcx.erase_regions(ct));
                 }
             }
         }
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 93cdf121fbe0f..43e4b7f08e22d 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -231,7 +231,8 @@ impl fmt::Debug for c_void {
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
-    windows
+    target_os = "uefi",
+    windows,
 ))]
 #[repr(transparent)]
 #[unstable(
@@ -254,7 +255,8 @@ pub struct VaListImpl<'f> {
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
-    windows
+    target_os = "uefi",
+    windows,
 ))]
 #[unstable(
     feature = "c_variadic",
@@ -276,7 +278,8 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
 #[cfg(all(
     target_arch = "aarch64",
     not(any(target_os = "macos", target_os = "ios")),
-    not(windows)
+    not(target_os = "uefi"),
+    not(windows),
 ))]
 #[repr(C)]
 #[derive(Debug)]
@@ -297,7 +300,7 @@ pub struct VaListImpl<'f> {
 }
 
 /// PowerPC ABI implementation of a `va_list`.
-#[cfg(all(target_arch = "powerpc", not(windows)))]
+#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
 #[repr(C)]
 #[derive(Debug)]
 #[unstable(
@@ -317,7 +320,7 @@ pub struct VaListImpl<'f> {
 }
 
 /// x86_64 ABI implementation of a `va_list`.
-#[cfg(all(target_arch = "x86_64", not(windows)))]
+#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
 #[repr(C)]
 #[derive(Debug)]
 #[unstable(
@@ -354,7 +357,8 @@ pub struct VaList<'a, 'f: 'a> {
         all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
         target_family = "wasm",
         target_arch = "asmjs",
-        windows
+        target_os = "uefi",
+        windows,
     ))]
     inner: VaListImpl<'f>,
 
@@ -363,7 +367,8 @@ pub struct VaList<'a, 'f: 'a> {
         any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
         not(target_family = "wasm"),
         not(target_arch = "asmjs"),
-        not(windows)
+        not(target_os = "uefi"),
+        not(windows),
     ))]
     inner: &'a mut VaListImpl<'f>,
 
@@ -375,7 +380,8 @@ pub struct VaList<'a, 'f: 'a> {
     all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
     target_family = "wasm",
     target_arch = "asmjs",
-    windows
+    target_os = "uefi",
+    windows,
 ))]
 #[unstable(
     feature = "c_variadic",
@@ -396,7 +402,8 @@ impl<'f> VaListImpl<'f> {
     any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
     not(target_family = "wasm"),
     not(target_arch = "asmjs"),
-    not(windows)
+    not(target_os = "uefi"),
+    not(windows),
 ))]
 #[unstable(
     feature = "c_variadic",
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 65b8df4299663..8e9189629db0d 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -210,6 +210,8 @@
 #![allow(unused_lifetimes)]
 // Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
+// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
+#![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))]
 // std may use features in a platform-specific way
 #![allow(unused_features)]
 #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 0a6a7cfe976cc..c70ac8c9806d6 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -159,6 +159,7 @@ use crate::cell::UnsafeCell;
 use crate::ffi::{CStr, CString};
 use crate::fmt;
 use crate::io;
+use crate::marker::PhantomData;
 use crate::mem;
 use crate::num::NonZeroU64;
 use crate::num::NonZeroUsize;
@@ -462,7 +463,7 @@ impl Builder {
     unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
         self,
         f: F,
-        scope_data: Option<&'scope scoped::ScopeData>,
+        scope_data: Option<Arc<scoped::ScopeData>>,
     ) -> io::Result<JoinInner<'scope, T>>
     where
         F: FnOnce() -> T,
@@ -479,8 +480,11 @@ impl Builder {
         }));
         let their_thread = my_thread.clone();
 
-        let my_packet: Arc<Packet<'scope, T>> =
-            Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
+        let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
+            scope: scope_data,
+            result: UnsafeCell::new(None),
+            _marker: PhantomData,
+        });
         let their_packet = my_packet.clone();
 
         let output_capture = crate::io::set_output_capture(None);
@@ -507,7 +511,7 @@ impl Builder {
             unsafe { *their_packet.result.get() = Some(try_result) };
         };
 
-        if let Some(scope_data) = scope_data {
+        if let Some(scope_data) = &my_packet.scope {
             scope_data.increment_num_running_threads();
         }
 
@@ -1298,8 +1302,9 @@ pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
 // An Arc to the packet is stored into a `JoinInner` which in turns is placed
 // in `JoinHandle`.
 struct Packet<'scope, T> {
-    scope: Option<&'scope scoped::ScopeData>,
+    scope: Option<Arc<scoped::ScopeData>>,
     result: UnsafeCell<Option<Result<T>>>,
+    _marker: PhantomData<Option<&'scope scoped::ScopeData>>,
 }
 
 // Due to the usage of `UnsafeCell` we need to manually implement Sync.
@@ -1330,7 +1335,7 @@ impl<'scope, T> Drop for Packet<'scope, T> {
             rtabort!("thread result panicked on drop");
         }
         // Book-keeping so the scope knows when it's done.
-        if let Some(scope) = self.scope {
+        if let Some(scope) = &self.scope {
             // Now that there will be no more user code running on this thread
             // that can use 'scope, mark the thread as 'finished'.
             // It's important we only do this after the `result` has been dropped,
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index a387a09dc8b15..e6dbf35bd0286 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -11,7 +11,7 @@ use crate::sync::Arc;
 /// See [`scope`] for details.
 #[stable(feature = "scoped_threads", since = "1.63.0")]
 pub struct Scope<'scope, 'env: 'scope> {
-    data: ScopeData,
+    data: Arc<ScopeData>,
     /// Invariance over 'scope, to make sure 'scope cannot shrink,
     /// which is necessary for soundness.
     ///
@@ -130,12 +130,14 @@ pub fn scope<'env, F, T>(f: F) -> T
 where
     F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T,
 {
+    // We put the `ScopeData` into an `Arc` so that other threads can finish their
+    // `decrement_num_running_threads` even after this function returns.
     let scope = Scope {
-        data: ScopeData {
+        data: Arc::new(ScopeData {
             num_running_threads: AtomicUsize::new(0),
             main_thread: current(),
             a_thread_panicked: AtomicBool::new(false),
-        },
+        }),
         env: PhantomData,
         scope: PhantomData,
     };
@@ -250,7 +252,7 @@ impl Builder {
         F: FnOnce() -> T + Send + 'scope,
         T: Send + 'scope,
     {
-        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?))
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(scope.data.clone())) }?))
     }
 }
 
diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs
index dca782c29c252..759a99c330c27 100644
--- a/src/bootstrap/cc_detect.rs
+++ b/src/bootstrap/cc_detect.rs
@@ -61,6 +61,30 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
     }
 }
 
+fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
+    let mut cfg = cc::Build::new();
+    cfg.cargo_metadata(false)
+        .opt_level(2)
+        .warnings(false)
+        .debug(false)
+        .target(&target.triple)
+        .host(&build.build.triple);
+    match build.crt_static(target) {
+        Some(a) => {
+            cfg.static_crt(a);
+        }
+        None => {
+            if target.contains("msvc") {
+                cfg.static_crt(true);
+            }
+            if target.contains("musl") {
+                cfg.static_flag(true);
+            }
+        }
+    }
+    cfg
+}
+
 pub fn find(build: &mut Build) {
     // For all targets we're going to need a C compiler for building some shims
     // and such as well as for being a linker for Rust code.
@@ -72,27 +96,7 @@ pub fn find(build: &mut Build) {
         .chain(iter::once(build.build))
         .collect::<HashSet<_>>();
     for target in targets.into_iter() {
-        let mut cfg = cc::Build::new();
-        cfg.cargo_metadata(false)
-            .opt_level(2)
-            .warnings(false)
-            .debug(false)
-            .target(&target.triple)
-            .host(&build.build.triple);
-        match build.crt_static(target) {
-            Some(a) => {
-                cfg.static_crt(a);
-            }
-            None => {
-                if target.contains("msvc") {
-                    cfg.static_crt(true);
-                }
-                if target.contains("musl") {
-                    cfg.static_flag(true);
-                }
-            }
-        }
-
+        let mut cfg = new_cc_build(build, target);
         let config = build.config.target_config.get(&target);
         if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
             cfg.compiler(cc);
@@ -112,15 +116,8 @@ pub fn find(build: &mut Build) {
 
         // If we use llvm-libunwind, we will need a C++ compiler as well for all targets
         // We'll need one anyways if the target triple is also a host triple
-        let mut cfg = cc::Build::new();
-        cfg.cargo_metadata(false)
-            .opt_level(2)
-            .warnings(false)
-            .debug(false)
-            .cpp(true)
-            .target(&target.triple)
-            .host(&build.build.triple);
-
+        let mut cfg = new_cc_build(build, target);
+        cfg.cpp(true);
         let cxx_configured = if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
             cfg.compiler(cxx);
             true
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 859d35b7d7ba1..40ff0381c8bc1 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -107,15 +107,11 @@ use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs::{self, File};
+use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
 use std::str;
 
-#[cfg(unix)]
-use std::os::unix::fs::symlink as symlink_file;
-#[cfg(windows)]
-use std::os::windows::fs::symlink_file;
-
 use filetime::FileTime;
 use once_cell::sync::OnceCell;
 
@@ -1460,7 +1456,7 @@ impl Build {
                 src = t!(fs::canonicalize(src));
             } else {
                 let link = t!(fs::read_link(src));
-                t!(symlink_file(link, dst));
+                t!(self.symlink_file(link, dst));
                 return;
             }
         }
@@ -1585,6 +1581,14 @@ impl Build {
         iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
     }
 
+    fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> {
+        #[cfg(unix)]
+        use std::os::unix::fs::symlink as symlink_file;
+        #[cfg(windows)]
+        use std::os::windows::fs::symlink_file;
+        if !self.config.dry_run { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
+    }
+
     fn remove(&self, f: &Path) {
         if self.config.dry_run {
             return;
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 9cd8b6d1455dd..b196b55c5e758 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -251,9 +251,7 @@ impl Step for Llvm {
             };
 
         builder.update_submodule(&Path::new("src").join("llvm-project"));
-        if builder.llvm_link_shared()
-            && (target.contains("windows") || target.contains("apple-darwin"))
-        {
+        if builder.llvm_link_shared() && target.contains("windows") {
             panic!("shared linking to LLVM is not currently supported on {}", target.triple);
         }
 
@@ -359,7 +357,9 @@ impl Step for Llvm {
         //
         // If we're not linking rustc to a dynamic LLVM, though, then don't link
         // tools to it.
-        if builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared() {
+        let llvm_link_shared =
+            builder.llvm_link_tools_dynamically(target) && builder.llvm_link_shared();
+        if llvm_link_shared {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
@@ -429,27 +429,35 @@ impl Step for Llvm {
             //        should use llvm-tblgen from there, also should verify that it
             //        actually exists most of the time in normal installs of LLVM.
             let host_bin = builder.llvm_out(builder.config.build).join("bin");
-            cfg.define("CMAKE_CROSSCOMPILING", "True");
             cfg.define("LLVM_TABLEGEN", host_bin.join("llvm-tblgen").with_extension(EXE_EXTENSION));
+            // LLVM_NM is required for cross compiling using MSVC
             cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION));
             cfg.define(
                 "LLVM_CONFIG_PATH",
                 host_bin.join("llvm-config").with_extension(EXE_EXTENSION),
             );
+            if builder.config.llvm_clang {
+                let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin");
+                let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION);
+                if !clang_tblgen.exists() {
+                    panic!("unable to find {}", clang_tblgen.display());
+                }
+                cfg.define("CLANG_TABLEGEN", clang_tblgen);
+            }
         }
 
-        if let Some(ref suffix) = builder.config.llvm_version_suffix {
+        let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix {
             // Allow version-suffix="" to not define a version suffix at all.
-            if !suffix.is_empty() {
-                cfg.define("LLVM_VERSION_SUFFIX", suffix);
-            }
+            if !suffix.is_empty() { Some(suffix.to_string()) } else { None }
         } else if builder.config.channel == "dev" {
             // Changes to a version suffix require a complete rebuild of the LLVM.
             // To avoid rebuilds during a time of version bump, don't include rustc
             // release number on the dev channel.
-            cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev");
+            Some("-rust-dev".to_string())
         } else {
-            let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel);
+            Some(format!("-rust-{}-{}", builder.version, builder.config.channel))
+        };
+        if let Some(ref suffix) = llvm_version_suffix {
             cfg.define("LLVM_VERSION_SUFFIX", suffix);
         }
 
@@ -478,6 +486,27 @@ impl Step for Llvm {
 
         cfg.build();
 
+        // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned
+        // libLLVM.dylib will be built. However, llvm-config will still look
+        // for a versioned path like libLLVM-14.dylib. Manually create a symbolic
+        // link to make llvm-config happy.
+        if llvm_link_shared && target.contains("apple-darwin") {
+            let mut cmd = Command::new(&build_llvm_config);
+            let version = output(cmd.arg("--version"));
+            let major = version.split('.').next().unwrap();
+            let lib_name = match llvm_version_suffix {
+                Some(s) => format!("lib/libLLVM-{}{}.dylib", major, s),
+                None => format!("lib/libLLVM-{}.dylib", major),
+            };
+
+            // The reason why we build the library path from llvm-config is because
+            // the output of llvm-config depends on its location in the file system.
+            // Make sure we create the symlink exactly where it's needed.
+            let llvm_base = build_llvm_config.parent().unwrap().parent().unwrap();
+            let lib_llvm = llvm_base.join(lib_name);
+            t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
+        }
+
         t!(stamp.write());
 
         build_llvm_config
@@ -526,6 +555,8 @@ fn configure_cmake(
     cfg.target(&target.triple).host(&builder.config.build.triple);
 
     if target != builder.config.build {
+        cfg.define("CMAKE_CROSSCOMPILING", "True");
+
         if target.contains("netbsd") {
             cfg.define("CMAKE_SYSTEM_NAME", "NetBSD");
         } else if target.contains("freebsd") {
@@ -543,6 +574,17 @@ fn configure_cmake(
         // Since, the LLVM itself makes rather limited use of version checks in
         // CMakeFiles (and then only in tests), and so far no issues have been
         // reported, the system version is currently left unset.
+
+        if target.contains("darwin") {
+            // Make sure that CMake does not build universal binaries on macOS.
+            // Explicitly specifiy the one single target architecture.
+            if target.starts_with("aarch64") {
+                // macOS uses a different name for building arm64
+                cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64");
+            } else {
+                cfg.define("CMAKE_OSX_ARCHITECTURES", target.triple.split('-').next().unwrap());
+            }
+        }
     }
 
     let sanitize_cc = |cc: &Path| {
diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
new file mode 100644
index 0000000000000..c5e86f17df741
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
@@ -0,0 +1,9 @@
+## `dwarf-version`
+
+This option controls the version of DWARF that the compiler emits, on platforms
+that use DWARF to encode debug information. It takes one of the following
+values:
+
+* `2`: DWARF version 2 (the default on certain platforms, like macOS).
+* `4`: DWARF version 4 (the default on certain platforms, like Linux).
+* `5`: DWARF version 5.
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 70dbfd4442540..c33e272774438 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -412,14 +412,15 @@ function loadCss(cssFileName) {
         window.hidePopoverMenus();
     }
 
-    const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
     function handleShortcut(ev) {
         // Don't interfere with browser shortcuts
+        const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
         if (ev.ctrlKey || ev.altKey || ev.metaKey || disableShortcuts) {
             return;
         }
 
-        if (document.activeElement.tagName === "INPUT") {
+        if (document.activeElement.tagName === "INPUT" &&
+            document.activeElement.type !== "checkbox") {
             switch (getVirtualKey(ev)) {
             case "Escape":
                 handleEscape(ev);
@@ -926,6 +927,7 @@ function loadCss(cssFileName) {
     function showHelp() {
         const menu = getHelpMenu(true);
         if (menu.style.display === "none") {
+            window.hidePopoverMenus();
             menu.style.display = "";
         }
     }
@@ -939,6 +941,8 @@ function loadCss(cssFileName) {
         const shouldShowHelp = menu.style.display === "none";
         if (shouldShowHelp) {
             showHelp();
+        } else {
+            window.hidePopoverMenus();
         }
     });
 
diff --git a/src/test/assembly/dwarf5.rs b/src/test/assembly/dwarf5.rs
new file mode 100644
index 0000000000000..f41e6bd55be7d
--- /dev/null
+++ b/src/test/assembly/dwarf5.rs
@@ -0,0 +1,20 @@
+// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5.
+// assembly-output: emit-asm
+// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5
+// needs-llvm-components: x86
+
+#![feature(no_core, lang_items)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn wibble() {}
+
+// CHECK: .section .debug_info
+// CHECK-NOT: .short 2
+// CHECK-NOT: .short 4
+// CHECK: .short 5
diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml
index ba2986e969a35..54f3790a76521 100644
--- a/src/test/rustdoc-gui/pocket-menu.goml
+++ b/src/test/rustdoc-gui/pocket-menu.goml
@@ -24,6 +24,11 @@ click: "#help-button"
 assert-css: ("#help-button .popover", {"display": "block"})
 assert-css: ("#settings-menu .popover", {"display": "none"})
 
+// Now verify that clicking the help menu again closes it.
+click: "#help-button"
+assert-css: ("#help-button .popover", {"display": "none"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
 // We check the borders color now:
 
 // Ayu theme
diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml
index 237a4751a8d66..c402c7991c8bb 100644
--- a/src/test/rustdoc-gui/settings.goml
+++ b/src/test/rustdoc-gui/settings.goml
@@ -121,6 +121,20 @@ local-storage: {"rustdoc-disable-shortcuts": "false"}
 click: ".setting-line:last-child .toggle .label"
 assert-local-storage: {"rustdoc-disable-shortcuts": "true"}
 
+// Make sure that "Disable keyboard shortcuts" actually took effect.
+press-key: "Escape"
+press-key: "?"
+assert-false: "#help-button .popover"
+wait-for-css: ("#settings-menu .popover", {"display": "block"})
+
+// Now turn keyboard shortcuts back on, and see if they work.
+click: ".setting-line:last-child .toggle .label"
+assert-local-storage: {"rustdoc-disable-shortcuts": "false"}
+press-key: "Escape"
+press-key: "?"
+wait-for-css: ("#help-button .popover", {"display": "block"})
+assert-css: ("#settings-menu .popover", {"display": "none"})
+
 // Now we go to the settings page to check that the CSS is loaded as expected.
 goto: file://|DOC_PATH|/settings.html
 wait-for: "#settings"
diff --git a/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs b/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs
new file mode 100644
index 0000000000000..2ae0ae70dd977
--- /dev/null
+++ b/src/test/ui/const-generics/try_unify_ignore_lifetimes.rs
@@ -0,0 +1,33 @@
+// check-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct Num<const N: usize>;
+
+trait NumT {
+    const VALUE: usize;
+}
+
+impl<const N: usize> NumT for Num<N> {
+    const VALUE: usize = N;
+}
+
+struct Foo<'a, N: NumT>(&'a [u32; N::VALUE]) where [(); N::VALUE]:;
+
+trait Bar {
+    type Size: NumT;
+
+    fn bar<'a>(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: {
+        todo!();
+    }
+}
+
+trait Baz<'a> {
+    type Size: NumT;
+
+    fn baz(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: {
+        todo!();
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/dst/dst-index.stderr b/src/test/ui/dst/dst-index.stderr
index 6bcd70cbaad45..d38af3f89c21b 100644
--- a/src/test/ui/dst/dst-index.stderr
+++ b/src/test/ui/dst/dst-index.stderr
@@ -1,14 +1,14 @@
-error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
+error[E0161]: cannot move a value of type `str`
   --> $DIR/dst-index.rs:31:5
    |
 LL |     S[0];
-   |     ^^^^
+   |     ^^^^ the size of `str` cannot be statically determined
 
-error[E0161]: cannot move a value of type dyn Debug: the size of dyn Debug cannot be statically determined
+error[E0161]: cannot move a value of type `dyn Debug`
   --> $DIR/dst-index.rs:34:5
    |
 LL |     T[0];
-   |     ^^^^
+   |     ^^^^ the size of `dyn Debug` cannot be statically determined
 
 error[E0507]: cannot move out of index of `S`
   --> $DIR/dst-index.rs:31:5
diff --git a/src/test/ui/error-codes/E0161.base.stderr b/src/test/ui/error-codes/E0161.base.stderr
index fb578cda17e9f..15d98b657a262 100644
--- a/src/test/ui/error-codes/E0161.base.stderr
+++ b/src/test/ui/error-codes/E0161.base.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+error[E0161]: cannot move a value of type `dyn Bar`
   --> $DIR/E0161.rs:16:5
    |
 LL |     x.f();
-   |     ^^^^^
+   |     ^^^^^ the size of `dyn Bar` cannot be statically determined
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
index 15e83ab5a347d..43e609cc59efb 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     v.t(|| {});
    |     ^^^^^^^^^^
    |
-   = note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
+   = note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed`
 
 error: higher-ranked lifetime error
   --> $DIR/issue-59311.rs:17:9
@@ -12,7 +12,7 @@ error: higher-ranked lifetime error
 LL |     v.t(|| {});
    |         ^^^^^
    |
-   = note: could not prove for<'a> &'a V: 'static
+   = note: could not prove `for<'a> &'a V: 'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/lifetimes/re-empty-in-error.stderr b/src/test/ui/lifetimes/re-empty-in-error.stderr
index 3a5ab62ab96f6..72bb0782f4b4f 100644
--- a/src/test/ui/lifetimes/re-empty-in-error.stderr
+++ b/src/test/ui/lifetimes/re-empty-in-error.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     foo(&10);
    |     ^^^^^^^^
    |
-   = note: could not prove for<'b, 'r> &'b (): 'r
+   = note: could not prove `for<'b, 'r> &'b (): 'r`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mir/issue-67947.rs b/src/test/ui/mir/issue-67947.rs
index 79e75e655ff1f..f73d38f80426f 100644
--- a/src/test/ui/mir/issue-67947.rs
+++ b/src/test/ui/mir/issue-67947.rs
@@ -1,6 +1,6 @@
 struct Bug {
     A: [(); { *"" }.len()],
-    //~^ ERROR: cannot move a value of type str
+    //~^ ERROR: cannot move a value of type `str`
     //~| ERROR: cannot move out of a shared reference
 }
 
diff --git a/src/test/ui/mir/issue-67947.stderr b/src/test/ui/mir/issue-67947.stderr
index d526218162076..7697a411eb481 100644
--- a/src/test/ui/mir/issue-67947.stderr
+++ b/src/test/ui/mir/issue-67947.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
+error[E0161]: cannot move a value of type `str`
   --> $DIR/issue-67947.rs:2:13
    |
 LL |     A: [(); { *"" }.len()],
-   |             ^^^^^^^
+   |             ^^^^^^^ the size of `str` cannot be statically determined
 
 error[E0507]: cannot move out of a shared reference
   --> $DIR/issue-67947.rs:2:15
diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.rs b/src/test/ui/object-safety/object-safety-by-value-self-use.rs
index f903f26c0901d..8e93c538217bb 100644
--- a/src/test/ui/object-safety/object-safety-by-value-self-use.rs
+++ b/src/test/ui/object-safety/object-safety-by-value-self-use.rs
@@ -12,7 +12,7 @@ trait Baz {
 }
 
 fn use_bar(t: Box<dyn Bar>) {
-    t.bar() //~ ERROR cannot move a value of type dyn Bar
+    t.bar() //~ ERROR cannot move a value of type `dyn Bar`
 }
 
 fn main() { }
diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr
index 7ccc0cbdd576b..94fdcdf263ae0 100644
--- a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr
+++ b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
+error[E0161]: cannot move a value of type `dyn Bar`
   --> $DIR/object-safety-by-value-self-use.rs:15:5
    |
 LL |     t.bar()
-   |     ^^^^^^^
+   |     ^^^^^^^ the size of `dyn Bar` cannot be statically determined
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/panic-runtime/auxiliary/needs-abort.rs b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs
new file mode 100644
index 0000000000000..8fad49b5e9d32
--- /dev/null
+++ b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
diff --git a/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs
new file mode 100644
index 0000000000000..d555b531986b0
--- /dev/null
+++ b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs
@@ -0,0 +1,13 @@
+// compile-flags:-C panic=unwind
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
+#![feature(c_unwind)]
+
+extern "C-unwind" fn foo() {}
+
+fn bar() {
+    let ptr: extern "C-unwind" fn() = foo;
+    ptr();
+}
diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.rs b/src/test/ui/panic-runtime/need-abort-got-unwind.rs
new file mode 100644
index 0000000000000..c72fb96e357f0
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-abort-got-unwind.rs
@@ -0,0 +1,9 @@
+// build-fail
+// needs-unwind
+// error-pattern:is incompatible with this crate's strategy of `unwind`
+// aux-build:needs-abort.rs
+// ignore-wasm32-bare compiled with panic=abort by default
+
+extern crate needs_abort;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.stderr b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr
new file mode 100644
index 0000000000000..d29c7875fd0ff
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.rs b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
new file mode 100644
index 0000000000000..6752ecf90d2f7
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
@@ -0,0 +1,9 @@
+// build-fail
+// error-pattern:is incompatible with this crate's strategy of `abort`
+// aux-build:needs-unwind.rs
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+extern crate needs_unwind;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
new file mode 100644
index 0000000000000..4c71df3ebc147
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
index 4af754c81f97c..7f4a8ed290ecf 100644
--- a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
+++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
@@ -2,9 +2,7 @@ error: cannot link together two panic runtimes: panic_runtime_unwind and panic_r
 
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
index c48caaf079077..23bfea6af15c1 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
@@ -1,6 +1,6 @@
 // build-fail
 // needs-unwind
-// error-pattern:is incompatible with this crate's strategy of `unwind`
+// error-pattern:is not compiled with this crate's panic strategy `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
 // ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
index d4fd2cca81fdc..d306ce6c5ea28 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
@@ -1,6 +1,4 @@
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
index 364a27a24eb70..014437b7f1b66 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
@@ -1,8 +1,6 @@
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/unsized/return-unsized-from-trait-method.rs b/src/test/ui/unsized/return-unsized-from-trait-method.rs
index ebe6edd101014..f053f4b0af89c 100644
--- a/src/test/ui/unsized/return-unsized-from-trait-method.rs
+++ b/src/test/ui/unsized/return-unsized-from-trait-method.rs
@@ -7,7 +7,7 @@ trait Foo {
 fn foo(f: Option<&dyn Foo>) {
     if let Some(f) = f {
         let _ = f.foo();
-        //~^ ERROR cannot move a value of type [u8]: the size of [u8] cannot be statically determined
+        //~^ ERROR cannot move a value of type `[u8]`
     }
 }
 
diff --git a/src/test/ui/unsized/return-unsized-from-trait-method.stderr b/src/test/ui/unsized/return-unsized-from-trait-method.stderr
index 4dd7cf5e02fc2..671d409937cac 100644
--- a/src/test/ui/unsized/return-unsized-from-trait-method.stderr
+++ b/src/test/ui/unsized/return-unsized-from-trait-method.stderr
@@ -1,8 +1,8 @@
-error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined
+error[E0161]: cannot move a value of type `[u8]`
   --> $DIR/return-unsized-from-trait-method.rs:9:17
    |
 LL |         let _ = f.foo();
-   |                 ^^^^^^^
+   |                 ^^^^^^^ the size of `[u8]` cannot be statically determined
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
index f02a368d4e097..ba72f74f20ce6 100644
--- a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
+++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
@@ -1,6 +1,10 @@
 // Test that the "C-unwind" ABI is feature-gated, and cannot be used when the
 // `c_unwind` feature gate is not used.
 
+#![allow(ffi_unwind_calls)]
+//~^ WARNING unknown lint: `ffi_unwind_calls`
+//~| WARNING unknown lint: `ffi_unwind_calls`
+
 extern "C-unwind" fn f() {}
 //~^ ERROR C-unwind ABI is experimental and subject to change [E0658]
 
diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
index f4c785a235f67..a67f46cd2e3b6 100644
--- a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
+++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
@@ -1,5 +1,16 @@
+warning: unknown lint: `ffi_unwind_calls`
+  --> $DIR/feature-gate-c-unwind.rs:4:1
+   |
+LL | #![allow(ffi_unwind_calls)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `ffi_unwind_calls` lint is unstable
+   = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
+   = help: add `#![feature(c_unwind)]` to the crate attributes to enable
+
 error[E0658]: C-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-c-unwind.rs:4:8
+  --> $DIR/feature-gate-c-unwind.rs:8:8
    |
 LL | extern "C-unwind" fn f() {}
    |        ^^^^^^^^^^
@@ -7,6 +18,16 @@ LL | extern "C-unwind" fn f() {}
    = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
    = help: add `#![feature(c_unwind)]` to the crate attributes to enable
 
-error: aborting due to previous error
+warning: unknown lint: `ffi_unwind_calls`
+  --> $DIR/feature-gate-c-unwind.rs:4:1
+   |
+LL | #![allow(ffi_unwind_calls)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `ffi_unwind_calls` lint is unstable
+   = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
+   = help: add `#![feature(c_unwind)]` to the crate attributes to enable
+
+error: aborting due to previous error; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs
new file mode 100644
index 0000000000000..67c20e9eac54e
--- /dev/null
+++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs
@@ -0,0 +1,25 @@
+// build-pass
+
+#![feature(c_unwind)]
+#![warn(ffi_unwind_calls)]
+
+mod foo {
+    #[no_mangle]
+    pub extern "C-unwind" fn foo() {}
+}
+
+extern "C-unwind" {
+    fn foo();
+}
+
+fn main() {
+    // Call to Rust function is fine.
+    foo::foo();
+    // Call to foreign function should warn.
+    unsafe { foo(); }
+    //~^ WARNING call to foreign function with FFI-unwind ABI
+    let ptr: extern "C-unwind" fn() = foo::foo;
+    // Call to function pointer should also warn.
+    ptr();
+    //~^ WARNING call to function pointer with FFI-unwind ABI
+}
diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr
new file mode 100644
index 0000000000000..cf8a7782e35ee
--- /dev/null
+++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr
@@ -0,0 +1,20 @@
+warning: call to foreign function with FFI-unwind ABI
+  --> $DIR/ffi-unwind-calls-lint.rs:19:14
+   |
+LL |     unsafe { foo(); }
+   |              ^^^^^ call to foreign function with FFI-unwind ABI
+   |
+note: the lint level is defined here
+  --> $DIR/ffi-unwind-calls-lint.rs:4:9
+   |
+LL | #![warn(ffi_unwind_calls)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: call to function pointer with FFI-unwind ABI
+  --> $DIR/ffi-unwind-calls-lint.rs:23:5
+   |
+LL |     ptr();
+   |     ^^^^^ call to function pointer with FFI-unwind ABI
+
+warning: 2 warnings emitted
+
diff --git a/triagebot.toml b/triagebot.toml
index 100dfd613f0cb..bebb583e100a4 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -219,7 +219,7 @@ changelog-branch = "master"
 
 [mentions."compiler/rustc_apfloat"]
 message = """
-Changes rustc_apfloat. rustc_apfloat is currently in limbo and you almost
+Changes rustc_apfloat. rustc_apfloat is currently in limbo and you almost \
 certainly don't want to change it (see #55993).
 """
 cc = ["@eddyb"]
@@ -258,22 +258,22 @@ cc = ["@GuillaumeGomez"]
 message = """
 Hey! It looks like you've submitted a new PR for the library teams!
 
-If this PR contains changes to any `rust-lang/rust` public library APIs then
-please comment with `@rustbot label +T-libs-api -T-libs` to tag it
-appropriately. If this PR contains changes to any unstable APIs please edit
-the PR description to add a link to the relevant [API Change
-Proposal](https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html)
-or [create one](https://github.com/rust-lang/libs-team/issues/new?assignees=&labels=api-change-proposal%2C+T-libs-api&template=api-change-proposal.md&title=%28My+API+Change+Proposal%29)
-if you haven't already. If you're unsure where your change falls no worries,
-just leave it as is and the reviewer will take a look and make a decision to
+If this PR contains changes to any `rust-lang/rust` public library APIs then \
+please comment with `@rustbot label +T-libs-api -T-libs` to tag it \
+appropriately. If this PR contains changes to any unstable APIs please edit \
+the PR description to add a link to the relevant [API Change \
+Proposal](https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html) \
+or [create one](https://github.com/rust-lang/libs-team/issues/new?assignees=&labels=api-change-proposal%2C+T-libs-api&template=api-change-proposal.md&title=%28My+API+Change+Proposal%29) \
+if you haven't already. If you're unsure where your change falls no worries, \
+just leave it as is and the reviewer will take a look and make a decision to \
 forward on if necessary.
 
 Examples of `T-libs-api` changes:
 
 * Stabilizing library features
-* Introducing insta-stable changes such as new implementations of existing
+* Introducing insta-stable changes such as new implementations of existing \
   stable traits on existing stable types
-* Introducing new or changing existing unstable library APIs (excluding
+* Introducing new or changing existing unstable library APIs (excluding \
   permanently unstable features / features without a tracking issue)
 * Changing public documentation in ways that create new stability guarantees
 * Changing observable runtime behavior of library APIs
@@ -300,8 +300,8 @@ cc = ["@Cldfire"]
 
 [mentions."src/rustdoc-json-types"]
 message = """
-rustdoc-json-types is a **public** (although nightly-only) API.
-If possible, consider changing `src/librustdoc/json/conversions.rs`;
+rustdoc-json-types is a **public** (although nightly-only) API. \
+If possible, consider changing `src/librustdoc/json/conversions.rs`; \
 otherwise, make sure you bump the `FORMAT_VERSION` constant.
 """
 cc = [