about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-03 19:18:43 +0000
committerbors <bors@rust-lang.org>2023-06-03 19:18:43 +0000
commit398fa2187c88de46c13c142f600064483a563c86 (patch)
tree74d42d4297d81015c6bc14c0ddd08cb88956d5d4
parent2f5e6bb817c115c067ff47453eb9aa89a0a31358 (diff)
parentd4f87d1e4f2b18bfc6eb01a9eef7b908fb9346eb (diff)
downloadrust-398fa2187c88de46c13c142f600064483a563c86.tar.gz
rust-398fa2187c88de46c13c142f600064483a563c86.zip
Auto merge of #112253 - matthiaskrgr:rollup-c37jpm5, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #111659 (suggest `Option::as_deref(_mut)` on type mismatch in option combinator if it passes typeck)
 - #111702 (Option::map_or_else: Show an example of integrating with Result)
 - #111878 (Fix codegen test suite for bare-metal-like targets)
 - #111969 (bootstrap: Make `clean` respect `dry-run`)
 - #111998 (Add other workspaces to `linkedProjects` in rust_analyzer_settings)
 - #112215 (only suppress coercion error if type is definitely unsized)
 - #112231 (Make sure the build.rustc version is either the same or 1 apart (revised))

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs104
-rw-r--r--library/core/src/option.rs21
-rw-r--r--src/bootstrap/Cargo.lock7
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/clean.rs4
-rw-r--r--src/bootstrap/config.rs45
-rw-r--r--src/bootstrap/setup.rs1
-rw-r--r--src/etc/rust_analyzer_settings.json9
-rw-r--r--src/tools/x/Cargo.lock4
-rw-r--r--tests/codegen/box-maybe-uninit-llvm14.rs2
-rw-r--r--tests/codegen/box-maybe-uninit.rs4
-rw-r--r--tests/codegen/call-metadata.rs2
-rw-r--r--tests/codegen/debug-column.rs4
-rw-r--r--tests/codegen/drop.rs1
-rw-r--r--tests/codegen/external-no-mangle-statics.rs32
-rw-r--r--tests/codegen/issues/issue-86106.rs4
-rw-r--r--tests/codegen/link_section.rs8
-rw-r--r--tests/codegen/mir-inlined-line-numbers.rs2
-rw-r--r--tests/codegen/naked-noinline.rs4
-rw-r--r--tests/codegen/personality_lifetimes.rs1
-rw-r--r--tests/codegen/ptr-read-metadata.rs16
-rw-r--r--tests/codegen/tuple-layout-opt.rs12
-rw-r--r--tests/codegen/union-abi.rs20
-rw-r--r--tests/codegen/unwind-abis/c-unwind-abi.rs1
-rw-r--r--tests/codegen/unwind-abis/cdecl-unwind-abi.rs1
-rw-r--r--tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs1
-rw-r--r--tests/codegen/unwind-abis/system-unwind-abi.rs1
-rw-r--r--tests/codegen/unwind-extern-exports.rs1
-rw-r--r--tests/codegen/unwind-extern-imports.rs1
-rw-r--r--tests/codegen/vec-shrink-panik.rs1
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs40
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr96
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.fixed30
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.rs30
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.stderr63
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch-2.rs11
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch-2.stderr15
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch.rs21
-rw-r--r--tests/ui/typeck/return-dyn-type-mismatch.stderr15
40 files changed, 586 insertions, 80 deletions
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 905781ec8f5..ba49e0c4161 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1595,7 +1595,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            unsized_return = self.is_return_ty_unsized(fcx, blk_id);
+                            unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                         if let Some(expression) = expression
                             && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
@@ -1614,8 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             None,
                         );
                         if !fcx.tcx.features().unsized_locals {
-                            let id = fcx.tcx.hir().parent_id(id);
-                            unsized_return = self.is_return_ty_unsized(fcx, id);
+                            unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
                     _ => {
@@ -1896,15 +1895,24 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
         err.help("you could instead create a new `enum` with a variant for each returned type");
     }
 
-    fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
-        if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
-            && let hir::FnRetTy::Return(ty) = fn_decl.output
-            && let ty = fcx.astconv().ast_ty_to_ty( ty)
-            && let ty::Dynamic(..) = ty.kind()
-        {
-            return true;
+    /// Checks whether the return type is unsized via an obligation, which makes
+    /// sure we consider `dyn Trait: Sized` where clauses, which are trivially
+    /// false but technically valid for typeck.
+    fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool {
+        if let Some(sig) = fcx.body_fn_sig() {
+            !fcx.predicate_may_hold(&Obligation::new(
+                fcx.tcx,
+                ObligationCause::dummy(),
+                fcx.param_env,
+                ty::TraitRef::new(
+                    fcx.tcx,
+                    fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
+                    [sig.output()],
+                ),
+            ))
+        } else {
+            false
         }
-        false
     }
 
     pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {
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 204d6fd043b..42038dbc3d8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
     error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
-    ErrorGuaranteed, MultiSpan, Style,
+    ErrorGuaranteed, MultiSpan, Style, SuggestionStyle,
 };
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -362,6 +362,15 @@ pub trait TypeErrCtxtExt<'tcx> {
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
+
+    fn suggest_option_method_if_applicable(
+        &self,
+        failed_pred: ty::Predicate<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+    );
+
     fn note_function_argument_obligation(
         &self,
         body_id: LocalDefId,
@@ -3521,15 +3530,92 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 err.replace_span_with(path.ident.span, true);
             }
         }
-        if let Some(Node::Expr(hir::Expr {
-            kind:
-                hir::ExprKind::Call(hir::Expr { span, .. }, _)
-                | hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..),
-            ..
-        })) = hir.find(call_hir_id)
+
+        if let Some(Node::Expr(expr)) = hir.find(call_hir_id) {
+            if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
+            | hir::ExprKind::MethodCall(
+                hir::PathSegment { ident: Ident { span, .. }, .. },
+                ..,
+            ) = expr.kind
+            {
+                if Some(*span) != err.span.primary_span() {
+                    err.span_label(*span, "required by a bound introduced by this call");
+                }
+            }
+
+            if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind {
+                self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr);
+            }
+        }
+    }
+
+    fn suggest_option_method_if_applicable(
+        &self,
+        failed_pred: ty::Predicate<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+    ) {
+        let tcx = self.tcx;
+        let infcx = self.infcx;
+        let Some(typeck_results) = self.typeck_results.as_ref() else { return };
+
+        // Make sure we're dealing with the `Option` type.
+        let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { return };
+        if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) {
+            return;
+        }
+
+        // Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`,
+        // then suggest `Option::as_deref(_mut)` if `U` can deref to `T`
+        if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { trait_ref, .. }))
+            = failed_pred.kind().skip_binder()
+            && tcx.is_fn_trait(trait_ref.def_id)
+            && let [self_ty, found_ty] = trait_ref.substs.as_slice()
+            && let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn())
+            && let fn_sig @ ty::FnSig {
+                abi: abi::Abi::Rust,
+                c_variadic: false,
+                unsafety: hir::Unsafety::Normal,
+                ..
+            } = fn_ty.fn_sig(tcx).skip_binder()
+
+            // Extract first param of fn sig with peeled refs, e.g. `fn(&T)` -> `T`
+            && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind())
+            && !target_ty.has_escaping_bound_vars()
+
+            // Extract first tuple element out of fn trait, e.g. `FnOnce<(U,)>` -> `U`
+            && let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind)
+            && let &[found_ty] = tys.as_slice()
+            && !found_ty.has_escaping_bound_vars()
+
+            // Extract `<U as Deref>::Target` assoc type and check that it is `T`
+            && let Some(deref_target_did) = tcx.lang_items().deref_target()
+            && let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
+            && let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection)
+            && deref_target == target_ty
         {
-            if Some(*span) != err.span.primary_span() {
-                err.span_label(*span, "required by a bound introduced by this call");
+            let help = if let hir::Mutability::Mut = needs_mut
+                && let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
+                && infcx
+                    .type_implements_trait(deref_mut_did, iter::once(found_ty), param_env)
+                    .must_apply_modulo_regions()
+            {
+                Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()"))
+            } else if let hir::Mutability::Not = needs_mut {
+                Some(("call `Option::as_deref()` first", ".as_deref()"))
+            } else {
+                None
+            };
+
+            if let Some((msg, sugg)) = help {
+                err.span_suggestion_with_style(
+                    expr.span.shrink_to_hi(),
+                    msg,
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways
+                );
             }
         }
     }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index ec1ef3cf43d..b93b40e3003 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -1138,7 +1138,7 @@ impl<T> Option<T> {
     /// Computes a default function result (if none), or
     /// applies a different function to the contained value (if any).
     ///
-    /// # Examples
+    /// # Basic examples
     ///
     /// ```
     /// let k = 21;
@@ -1149,6 +1149,25 @@ impl<T> Option<T> {
     /// let x: Option<&str> = None;
     /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
     /// ```
+    ///
+    /// # Handling a Result-based fallback
+    ///
+    /// A somewhat common occurrence when dealing with optional values
+    /// in combination with [`Result<T, E>`] is the case where one wants to invoke
+    /// a fallible fallback if the option is not present.  This example
+    /// parses a command line argument (if present), or the contents of a file to
+    /// an integer.  However, unlike accessing the command line argument, reading
+    /// the file is fallible, so it must be wrapped with `Ok`.
+    ///
+    /// ```no_run
+    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+    /// let v: u64 = std::env::args()
+    ///    .nth(1)
+    ///    .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)?
+    ///    .parse()?;
+    /// #   Ok(())
+    /// # }
+    /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 311ac175160..8f8778efee7 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -58,6 +58,7 @@ dependencies = [
  "once_cell",
  "opener",
  "pretty_assertions",
+ "semver",
  "serde",
  "serde_derive",
  "serde_json",
@@ -646,6 +647,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
 name = "serde"
 version = "1.0.160"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 70ade776d7d..367c6190967 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -57,6 +57,7 @@ walkdir = "2"
 sysinfo = { version = "0.26.0", optional = true }
 clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
 clap_complete = "4.2.2"
+semver = "1.0.17"
 
 # Solaris doesn't support flock() and thus fd-lock is not option now
 [target.'cfg(not(target_os = "solaris"))'.dependencies]
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs
index 0d9fd56b038..c1d867a0bd1 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/clean.rs
@@ -85,6 +85,10 @@ clean_crate_tree! {
 }
 
 fn clean_default(build: &Build, all: bool) {
+    if build.config.dry_run() {
+        return;
+    }
+
     rm_rf("tmp".as_ref());
 
     if all {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 45ad1547eb7..8ea7e836375 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -25,6 +25,7 @@ use crate::flags::{Color, Flags, Warnings};
 use crate::util::{exe, output, t};
 use build_helper::detail_exit_macro;
 use once_cell::sync::OnceCell;
+use semver::Version;
 use serde::{Deserialize, Deserializer};
 use serde_derive::Deserialize;
 
@@ -1114,10 +1115,14 @@ impl Config {
             config.out = crate::util::absolute(&config.out);
         }
 
-        config.initial_rustc = build.rustc.map(PathBuf::from).unwrap_or_else(|| {
+        config.initial_rustc = if let Some(rustc) = build.rustc {
+            config.check_build_rustc_version(&rustc);
+            PathBuf::from(rustc)
+        } else {
             config.download_beta_toolchain();
             config.out.join(config.build.triple).join("stage0/bin/rustc")
-        });
+        };
+
         config.initial_cargo = build
             .cargo
             .map(|cargo| {
@@ -1779,6 +1784,42 @@ impl Config {
         self.rust_codegen_backends.get(0).cloned()
     }
 
+    pub fn check_build_rustc_version(&self, rustc_path: &str) {
+        if self.dry_run() {
+            return;
+        }
+
+        // check rustc version is same or lower with 1 apart from the building one
+        let mut cmd = Command::new(rustc_path);
+        cmd.arg("--version");
+        let rustc_output = output(&mut cmd)
+            .lines()
+            .next()
+            .unwrap()
+            .split(' ')
+            .nth(1)
+            .unwrap()
+            .split('-')
+            .next()
+            .unwrap()
+            .to_owned();
+        let rustc_version = Version::parse(&rustc_output.trim()).unwrap();
+        let source_version =
+            Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim())
+                .unwrap();
+        if !(source_version == rustc_version
+            || (source_version.major == rustc_version.major
+                && source_version.minor == rustc_version.minor + 1))
+        {
+            let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
+            eprintln!(
+                "Unexpected rustc version: {}, we should use {}/{} to build source with {}",
+                rustc_version, prev_version, source_version, source_version
+            );
+            detail_exit_macro!(1);
+        }
+    }
+
     /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
     fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> {
         // If `download-rustc` is not set, default to rebuilding.
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 9b26d3f0a66..c604c63a4dd 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -31,6 +31,7 @@ static SETTINGS_HASHES: &[&str] = &[
     "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
     "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
     "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
+    "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
 ];
 static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
 
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index dd01bfaa725..d9c4645f0b3 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -7,7 +7,14 @@
         "check",
         "--json-output"
     ],
-    "rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
+    "rust-analyzer.linkedProjects": [
+        "Cargo.toml",
+        "src/tools/x/Cargo.toml",
+        "src/bootstrap/Cargo.toml",
+        "src/tools/rust-analyzer/Cargo.toml",
+        "compiler/rustc_codegen_cranelift/Cargo.toml",
+        "compiler/rustc_codegen_gcc/Cargo.toml"
+    ],
     "rust-analyzer.rustfmt.overrideCommand": [
         "./build/host/rustfmt/bin/rustfmt",
         "--edition=2021"
diff --git a/src/tools/x/Cargo.lock b/src/tools/x/Cargo.lock
index 723d6cb25ed..09e5c750749 100644
--- a/src/tools/x/Cargo.lock
+++ b/src/tools/x/Cargo.lock
@@ -1,5 +1,7 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+version = 3
+
 [[package]]
 name = "x"
-version = "0.1.0"
+version = "0.1.1"
diff --git a/tests/codegen/box-maybe-uninit-llvm14.rs b/tests/codegen/box-maybe-uninit-llvm14.rs
index b0c88f76c43..c9f88fb3fe4 100644
--- a/tests/codegen/box-maybe-uninit-llvm14.rs
+++ b/tests/codegen/box-maybe-uninit-llvm14.rs
@@ -31,4 +31,4 @@ pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
 // Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above. We don't check the attributes here because we can't rely
 // on all of them being set until LLVM 15.
-// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
+// CHECK: declare {{(dso_local )?}}noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
diff --git a/tests/codegen/box-maybe-uninit.rs b/tests/codegen/box-maybe-uninit.rs
index 2f88966996a..5c08b5832ad 100644
--- a/tests/codegen/box-maybe-uninit.rs
+++ b/tests/codegen/box-maybe-uninit.rs
@@ -28,6 +28,6 @@ pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
 
 // Hide the `allocalign` attribute in the declaration of __rust_alloc
 // from the CHECK-NOT above, and also verify the attributes got set reasonably.
-// CHECK: declare noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
+// CHECK: declare {{(dso_local )?}}noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
 
-// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
+// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} }
diff --git a/tests/codegen/call-metadata.rs b/tests/codegen/call-metadata.rs
index 1c30c08d3b2..07cc0c96371 100644
--- a/tests/codegen/call-metadata.rs
+++ b/tests/codegen/call-metadata.rs
@@ -6,7 +6,7 @@
 #![crate_type = "lib"]
 
 pub fn test() {
-    // CHECK: call noundef i8 @some_true(), !range [[R0:![0-9]+]]
+    // CHECK: call noundef i8 @some_true(){{( #[0-9]+)?}}, !range [[R0:![0-9]+]]
     // CHECK: [[R0]] = !{i8 0, i8 3}
     some_true();
 }
diff --git a/tests/codegen/debug-column.rs b/tests/codegen/debug-column.rs
index e61642b8e1b..f3b19a2eb2f 100644
--- a/tests/codegen/debug-column.rs
+++ b/tests/codegen/debug-column.rs
@@ -6,11 +6,11 @@
 fn main() {
     unsafe {
         // Column numbers are 1-based. Regression test for #65437.
-        // CHECK: call void @giraffe(), !dbg [[A:!.*]]
+        // CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]]
         giraffe();
 
         // Column numbers use byte offests. Regression test for #67360
-        // CHECK: call void @turtle(), !dbg [[B:!.*]]
+        // CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]]
 /* ż */ turtle();
 
         // CHECK: [[A]] = !DILocation(line: 10, column: 9,
diff --git a/tests/codegen/drop.rs b/tests/codegen/drop.rs
index 99402827158..3615ef47b53 100644
--- a/tests/codegen/drop.rs
+++ b/tests/codegen/drop.rs
@@ -1,4 +1,5 @@
 // ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind - this test verifies the amount of drop calls when unwinding is used
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/external-no-mangle-statics.rs b/tests/codegen/external-no-mangle-statics.rs
index c6ecb7aa96a..48023a2a901 100644
--- a/tests/codegen/external-no-mangle-statics.rs
+++ b/tests/codegen/external-no-mangle-statics.rs
@@ -6,72 +6,72 @@
 // `#[no_mangle]`d static variables always have external linkage, i.e., no `internal` in their
 // definitions
 
-// CHECK: @A = local_unnamed_addr constant
+// CHECK: @A = {{(dso_local )?}}local_unnamed_addr constant
 #[no_mangle]
 static A: u8 = 0;
 
-// CHECK: @B = local_unnamed_addr global
+// CHECK: @B = {{(dso_local )?}}local_unnamed_addr global
 #[no_mangle]
 static mut B: u8 = 0;
 
-// CHECK: @C = local_unnamed_addr constant
+// CHECK: @C = {{(dso_local )?}}local_unnamed_addr constant
 #[no_mangle]
 pub static C: u8 = 0;
 
-// CHECK: @D = local_unnamed_addr global
+// CHECK: @D = {{(dso_local )?}}local_unnamed_addr global
 #[no_mangle]
 pub static mut D: u8 = 0;
 
 mod private {
-    // CHECK: @E = local_unnamed_addr constant
+    // CHECK: @E = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static E: u8 = 0;
 
-    // CHECK: @F = local_unnamed_addr global
+    // CHECK: @F = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut F: u8 = 0;
 
-    // CHECK: @G = local_unnamed_addr constant
+    // CHECK: @G = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static G: u8 = 0;
 
-    // CHECK: @H = local_unnamed_addr global
+    // CHECK: @H = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut H: u8 = 0;
 }
 
 const HIDDEN: () = {
-    // CHECK: @I = local_unnamed_addr constant
+    // CHECK: @I = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static I: u8 = 0;
 
-    // CHECK: @J = local_unnamed_addr global
+    // CHECK: @J = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut J: u8 = 0;
 
-    // CHECK: @K = local_unnamed_addr constant
+    // CHECK: @K = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static K: u8 = 0;
 
-    // CHECK: @L = local_unnamed_addr global
+    // CHECK: @L = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut L: u8 = 0;
 };
 
 fn x() {
-    // CHECK: @M = local_unnamed_addr constant
+    // CHECK: @M = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     static M: fn() = x;
 
-    // CHECK: @N = local_unnamed_addr global
+    // CHECK: @N = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     static mut N: u8 = 0;
 
-    // CHECK: @O = local_unnamed_addr constant
+    // CHECK: @O = {{(dso_local )?}}local_unnamed_addr constant
     #[no_mangle]
     pub static O: u8 = 0;
 
-    // CHECK: @P = local_unnamed_addr global
+    // CHECK: @P = {{(dso_local )?}}local_unnamed_addr global
     #[no_mangle]
     pub static mut P: u8 = 0;
 }
diff --git a/tests/codegen/issues/issue-86106.rs b/tests/codegen/issues/issue-86106.rs
index c0be7fab2f3..be5034dcfbd 100644
--- a/tests/codegen/issues/issue-86106.rs
+++ b/tests/codegen/issues/issue-86106.rs
@@ -7,7 +7,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK-LABEL: define void @string_new
+// CHECK-LABEL: define {{(dso_local )?}}void @string_new
 #[no_mangle]
 pub fn string_new() -> String {
     // CHECK: store ptr inttoptr
@@ -17,7 +17,7 @@ pub fn string_new() -> String {
     String::new()
 }
 
-// CHECK-LABEL: define void @empty_to_string
+// CHECK-LABEL: define {{(dso_local )?}}void @empty_to_string
 #[no_mangle]
 pub fn empty_to_string() -> String {
     // CHECK: store ptr inttoptr
diff --git a/tests/codegen/link_section.rs b/tests/codegen/link_section.rs
index 88b8692b0ac..2b26b604ad3 100644
--- a/tests/codegen/link_section.rs
+++ b/tests/codegen/link_section.rs
@@ -3,7 +3,7 @@
 
 #![crate_type = "lib"]
 
-// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = {{(dso_local )?}}constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
 #[no_mangle]
 #[link_section = ".test_one"]
 #[cfg(target_endian = "little")]
@@ -19,17 +19,17 @@ pub enum E {
     B(f32)
 }
 
-// CHECK: @VAR2 = constant {{.*}}, section ".test_two"
+// CHECK: @VAR2 = {{(dso_local )?}}constant {{.*}}, section ".test_two"
 #[no_mangle]
 #[link_section = ".test_two"]
 pub static VAR2: E = E::A(666);
 
-// CHECK: @VAR3 = constant {{.*}}, section ".test_three"
+// CHECK: @VAR3 = {{(dso_local )?}}constant {{.*}}, section ".test_three"
 #[no_mangle]
 #[link_section = ".test_three"]
 pub static VAR3: E = E::B(1.);
 
-// CHECK: define void @fn1() {{.*}} section ".test_four" {
+// CHECK: define {{(dso_local )?}}void @fn1() {{.*}} section ".test_four" {
 #[no_mangle]
 #[link_section = ".test_four"]
 pub fn fn1() {}
diff --git a/tests/codegen/mir-inlined-line-numbers.rs b/tests/codegen/mir-inlined-line-numbers.rs
index 19d83f0eee7..d13527b9521 100644
--- a/tests/codegen/mir-inlined-line-numbers.rs
+++ b/tests/codegen/mir-inlined-line-numbers.rs
@@ -19,7 +19,7 @@ pub fn example() {
 }
 
 // CHECK-LABEL: @example
-// CHECK:   tail call void @bar(), !dbg [[DBG_ID:![0-9]+]]
+// CHECK:   tail call void @bar(){{( #[0-9]+)?}}, !dbg [[DBG_ID:![0-9]+]]
 // CHECK: [[DBG_ID]] = !DILocation(line: 7,
 // CHECK-SAME:                     inlinedAt: [[INLINE_ID:![0-9]+]])
 // CHECK: [[INLINE_ID]] = !DILocation(line: 18,
diff --git a/tests/codegen/naked-noinline.rs b/tests/codegen/naked-noinline.rs
index c0ac69f4ed7..5cfb500c0ef 100644
--- a/tests/codegen/naked-noinline.rs
+++ b/tests/codegen/naked-noinline.rs
@@ -12,7 +12,7 @@ use std::arch::asm;
 pub unsafe extern "C" fn f() {
     // Check that f has naked and noinline attributes.
     //
-    // CHECK:       define void @f() unnamed_addr [[ATTR:#[0-9]+]]
+    // CHECK:       define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]]
     // CHECK-NEXT:  start:
     // CHECK-NEXT:    call void asm
     asm!("", options(noreturn));
@@ -22,7 +22,7 @@ pub unsafe extern "C" fn f() {
 pub unsafe fn g() {
     // Check that call to f is not inlined.
     //
-    // CHECK-LABEL: define void @g()
+    // CHECK-LABEL: define {{(dso_local )?}}void @g()
     // CHECK-NEXT:  start:
     // CHECK-NEXT:    call void @f()
     f();
diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs
index 2104022f578..9ff7a9b3e88 100644
--- a/tests/codegen/personality_lifetimes.rs
+++ b/tests/codegen/personality_lifetimes.rs
@@ -1,5 +1,6 @@
 // ignore-msvc
 // ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind
 
 // compile-flags: -O -C no-prepopulate-passes
 
diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs
index e1e3272662c..73d1db6df27 100644
--- a/tests/codegen/ptr-read-metadata.rs
+++ b/tests/codegen/ptr-read-metadata.rs
@@ -9,7 +9,7 @@
 
 use std::mem::MaybeUninit;
 
-// CHECK-LABEL: define noundef i8 @copy_byte(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @copy_byte(
 #[no_mangle]
 pub unsafe fn copy_byte(p: *const u8) -> u8 {
     // CHECK-NOT: load
@@ -19,7 +19,7 @@ pub unsafe fn copy_byte(p: *const u8) -> u8 {
     *p
 }
 
-// CHECK-LABEL: define noundef i8 @read_byte(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte(
 #[no_mangle]
 pub unsafe fn read_byte(p: *const u8) -> u8 {
     // CHECK-NOT: load
@@ -29,7 +29,7 @@ pub unsafe fn read_byte(p: *const u8) -> u8 {
     p.read()
 }
 
-// CHECK-LABEL: define i8 @read_byte_maybe_uninit(
+// CHECK-LABEL: define {{(dso_local )?}}i8 @read_byte_maybe_uninit(
 #[no_mangle]
 pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit<u8>) -> MaybeUninit<u8> {
     // CHECK-NOT: load
@@ -39,7 +39,7 @@ pub unsafe fn read_byte_maybe_uninit(p: *const MaybeUninit<u8>) -> MaybeUninit<u
     p.read()
 }
 
-// CHECK-LABEL: define noundef i8 @read_byte_assume_init(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i8 @read_byte_assume_init(
 #[no_mangle]
 pub unsafe fn read_byte_assume_init(p: &MaybeUninit<u8>) -> u8 {
     // CHECK-NOT: load
@@ -49,7 +49,7 @@ pub unsafe fn read_byte_assume_init(p: &MaybeUninit<u8>) -> u8 {
     p.assume_init_read()
 }
 
-// CHECK-LABEL: define noundef i32 @copy_char(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @copy_char(
 #[no_mangle]
 pub unsafe fn copy_char(p: *const char) -> char {
     // CHECK-NOT: load
@@ -60,7 +60,7 @@ pub unsafe fn copy_char(p: *const char) -> char {
     *p
 }
 
-// CHECK-LABEL: define noundef i32 @read_char(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @read_char(
 #[no_mangle]
 pub unsafe fn read_char(p: *const char) -> char {
     // CHECK-NOT: load
@@ -71,7 +71,7 @@ pub unsafe fn read_char(p: *const char) -> char {
     p.read()
 }
 
-// CHECK-LABEL: define i32 @read_char_maybe_uninit(
+// CHECK-LABEL: define {{(dso_local )?}}i32 @read_char_maybe_uninit(
 #[no_mangle]
 pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit<char>) -> MaybeUninit<char> {
     // CHECK-NOT: load
@@ -82,7 +82,7 @@ pub unsafe fn read_char_maybe_uninit(p: *const MaybeUninit<char>) -> MaybeUninit
     p.read()
 }
 
-// CHECK-LABEL: define noundef i32 @read_char_assume_init(
+// CHECK-LABEL: define {{(dso_local )?}}noundef i32 @read_char_assume_init(
 #[no_mangle]
 pub unsafe fn read_char_assume_init(p: &MaybeUninit<char>) -> char {
     // CHECK-NOT: load
diff --git a/tests/codegen/tuple-layout-opt.rs b/tests/codegen/tuple-layout-opt.rs
index 35f76085145..309fe1d5ec9 100644
--- a/tests/codegen/tuple-layout-opt.rs
+++ b/tests/codegen/tuple-layout-opt.rs
@@ -6,31 +6,31 @@
 #![crate_type="lib"]
 
 type ScalarZstLast = (u128, ());
-// CHECK: define i128 @test_ScalarZstLast(i128 %_1)
+// CHECK: define {{(dso_local )?}}i128 @test_ScalarZstLast(i128 %_1)
 #[no_mangle]
 pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} }
 
 type ScalarZstFirst = ((), u128);
-// CHECK: define i128 @test_ScalarZstFirst(i128 %_1)
+// CHECK: define {{(dso_local )?}}i128 @test_ScalarZstFirst(i128 %_1)
 #[no_mangle]
 pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} }
 
 type ScalarPairZstLast = (u8, u128, ());
-// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1)
+// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1)
 #[no_mangle]
 pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} }
 
 type ScalarPairZstFirst = ((), u8, u128);
-// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1)
+// CHECK: define {{(dso_local )?}}{ i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1)
 #[no_mangle]
 pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} }
 
 type ScalarPairLotsOfZsts = ((), u8, (), u128, ());
-// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1)
+// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1)
 #[no_mangle]
 pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} }
 
 type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ());
-// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1)
+// CHECK: define {{(dso_local )?}}{ i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1)
 #[no_mangle]
 pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} }
diff --git a/tests/codegen/union-abi.rs b/tests/codegen/union-abi.rs
index c18f2a49fc3..8481ca8ccfa 100644
--- a/tests/codegen/union-abi.rs
+++ b/tests/codegen/union-abi.rs
@@ -17,60 +17,60 @@ pub struct i64x4(i64, i64, i64, i64);
 #[derive(Copy, Clone)]
 pub union UnionI64x4{ a:(), b: i64x4 }
 
-// CHECK: define void @test_UnionI64x4({{<4 x i64>\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4({{<4 x i64>\*|ptr}} {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4(_: UnionI64x4) { loop {} }
 
 pub union UnionI64x4_{ a: i64x4, b: (), c:i64x4, d: Unhab, e: ((),()), f: UnionI64x4 }
 
-// CHECK: define void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4_({{<4 x i64>\*|ptr}} {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4_(_: UnionI64x4_) { loop {} }
 
 pub union UnionI64x4I64{ a: i64x4, b: i64 }
 
-// CHECK: define void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4I64({{%UnionI64x4I64\*|ptr}} {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4I64(_: UnionI64x4I64) { loop {} }
 
 pub union UnionI64x4Tuple{ a: i64x4, b: (i64, i64, i64, i64) }
 
-// CHECK: define void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_UnionI64x4Tuple({{%UnionI64x4Tuple\*|ptr}} {{.*}} %_1)
 #[no_mangle]
 pub fn test_UnionI64x4Tuple(_: UnionI64x4Tuple) { loop {} }
 
 
 pub union UnionF32{a:f32}
 
-// CHECK: define float @test_UnionF32(float %_1)
+// CHECK: define {{(dso_local )?}}float @test_UnionF32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
 
 pub union UnionF32F32{a:f32, b:f32}
 
-// CHECK: define float @test_UnionF32F32(float %_1)
+// CHECK: define {{(dso_local )?}}float @test_UnionF32F32(float %_1)
 #[no_mangle]
 pub fn test_UnionF32F32(_: UnionF32F32) -> UnionF32F32 { loop {} }
 
 pub union UnionF32U32{a:f32, b:u32}
 
-// CHECK: define i32 @test_UnionF32U32(i32{{( %0)?}})
+// CHECK: define {{(dso_local )?}}i32 @test_UnionF32U32(i32{{( %0)?}})
 #[no_mangle]
 pub fn test_UnionF32U32(_: UnionF32U32) -> UnionF32U32 { loop {} }
 
 pub union UnionU128{a:u128}
-// CHECK: define i128 @test_UnionU128(i128 %_1)
+// CHECK: define {{(dso_local )?}}i128 @test_UnionU128(i128 %_1)
 #[no_mangle]
 pub fn test_UnionU128(_: UnionU128) -> UnionU128 { loop {} }
 
 #[repr(C)]
 pub union CUnionU128{a:u128}
-// CHECK: define void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1)
+// CHECK: define {{(dso_local )?}}void @test_CUnionU128({{%CUnionU128\*|ptr}} {{.*}} %_1)
 #[no_mangle]
 pub fn test_CUnionU128(_: CUnionU128) { loop {} }
 
 pub union UnionBool { b:bool }
-// CHECK: define noundef zeroext i1 @test_UnionBool(i8 %b)
+// CHECK: define {{(dso_local )?}}noundef zeroext i1 @test_UnionBool(i8 %b)
 #[no_mangle]
 pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b }  }
 // CHECK: %0 = trunc i8 %b to i1
diff --git a/tests/codegen/unwind-abis/c-unwind-abi.rs b/tests/codegen/unwind-abis/c-unwind-abi.rs
index e258dbcacd2..fa5b6bad75c 100644
--- a/tests/codegen/unwind-abis/c-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/c-unwind-abi.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C opt-level=0
+// needs-unwind
 
 // Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern
 // functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above
diff --git a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
index 19a7228839a..64746d32175 100644
--- a/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/cdecl-unwind-abi.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C opt-level=0
+// needs-unwind
 
 // Test that `nounwind` attributes are correctly applied to exported `cdecl` and
 // `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
index c1c5bbdda34..dc3911cd4eb 100644
--- a/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
+++ b/tests/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs
@@ -1,5 +1,6 @@
 // compile-flags: -C opt-level=0
 // ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind
 
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/unwind-abis/system-unwind-abi.rs b/tests/codegen/unwind-abis/system-unwind-abi.rs
index 2591c1d4814..f274a33b099 100644
--- a/tests/codegen/unwind-abis/system-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/system-unwind-abi.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C opt-level=0
+// needs-unwind
 
 // Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind`
 // extern functions. `system-unwind` functions MUST NOT have this attribute. We disable
diff --git a/tests/codegen/unwind-extern-exports.rs b/tests/codegen/unwind-extern-exports.rs
index 6ac3c079f81..4e1e719d5cd 100644
--- a/tests/codegen/unwind-extern-exports.rs
+++ b/tests/codegen/unwind-extern-exports.rs
@@ -1,5 +1,6 @@
 // compile-flags: -C opt-level=0
 // ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind
 
 #![crate_type = "lib"]
 #![feature(c_unwind)]
diff --git a/tests/codegen/unwind-extern-imports.rs b/tests/codegen/unwind-extern-imports.rs
index e33e3e80521..260dcc628cc 100644
--- a/tests/codegen/unwind-extern-imports.rs
+++ b/tests/codegen/unwind-extern-imports.rs
@@ -1,5 +1,6 @@
 // compile-flags: -C no-prepopulate-passes
 // ignore-wasm32-bare compiled with panic=abort by default
+// needs-unwind
 
 #![crate_type = "lib"]
 #![feature(c_unwind)]
diff --git a/tests/codegen/vec-shrink-panik.rs b/tests/codegen/vec-shrink-panik.rs
index 88b7edff260..606d68ff3ab 100644
--- a/tests/codegen/vec-shrink-panik.rs
+++ b/tests/codegen/vec-shrink-panik.rs
@@ -5,6 +5,7 @@
 // [new]min-llvm-version: 17
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
+// needs-unwind
 #![crate_type = "lib"]
 #![feature(shrink_to)]
 
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
new file mode 100644
index 00000000000..cc9ba5514fe
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
@@ -0,0 +1,40 @@
+fn produces_string() -> Option<String> {
+    Some("my cool string".to_owned())
+}
+
+fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
+    Some(())
+}
+
+fn no_args() -> Option<()> {
+    Some(())
+}
+
+fn generic_ref<T>(_: &T) -> Option<()> {
+    Some(())
+}
+
+extern "C" fn takes_str_but_wrong_abi(_: &str) -> Option<()> {
+    Some(())
+}
+
+unsafe fn takes_str_but_unsafe(_: &str) -> Option<()> {
+    Some(())
+}
+
+struct TypeWithoutDeref;
+
+fn main() {
+    let _ = produces_string().and_then(takes_str_but_too_many_refs);
+    //~^ ERROR type mismatch in function arguments
+    let _ = produces_string().and_then(takes_str_but_wrong_abi);
+    //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
+    let _ = produces_string().and_then(takes_str_but_unsafe);
+    //~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
+    let _ = produces_string().and_then(no_args);
+    //~^ ERROR function is expected to take 1 argument, but it takes 0 arguments
+    let _ = produces_string().and_then(generic_ref);
+    //~^ ERROR type mismatch in function arguments
+    let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
+    //~^ ERROR type mismatch in function arguments
+}
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
new file mode 100644
index 00000000000..079909eb48d
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
@@ -0,0 +1,96 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef-unfixable.rs:28:40
+   |
+LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
+   | ------------------------------------------------------ found signature defined here
+...
+LL |     let _ = produces_string().and_then(takes_str_but_too_many_refs);
+   |                               -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a, 'b> fn(&'a &'b str) -> _`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
+  --> $DIR/suggest-option-asderef-unfixable.rs:30:40
+   |
+LL |     let _ = produces_string().and_then(takes_str_but_wrong_abi);
+   |                               -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `FnOnce<(String,)>` is not implemented for fn item `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
+  --> $DIR/suggest-option-asderef-unfixable.rs:32:40
+   |
+LL |     let _ = produces_string().and_then(takes_str_but_unsafe);
+   |                               -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `FnOnce<(String,)>` is not implemented for fn item `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
+   = note: unsafe function cannot be called generically without an unsafe block
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
+  --> $DIR/suggest-option-asderef-unfixable.rs:34:40
+   |
+LL | fn no_args() -> Option<()> {
+   | -------------------------- takes 0 arguments
+...
+LL |     let _ = produces_string().and_then(no_args);
+   |                               -------- ^^^^^^^ expected function that takes 1 argument
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef-unfixable.rs:36:40
+   |
+LL | fn generic_ref<T>(_: &T) -> Option<()> {
+   | -------------------------------------- found signature defined here
+...
+LL |     let _ = produces_string().and_then(generic_ref);
+   |                               -------- ^^^^^^^^^^^ expected due to this
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a> fn(&'a _) -> _`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: do not borrow the argument
+   |
+LL - fn generic_ref<T>(_: &T) -> Option<()> {
+LL + fn generic_ref<T>(_: T) -> Option<()> {
+   |
+
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef-unfixable.rs:38:45
+   |
+LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
+   | ------------------------------------------------------ found signature defined here
+...
+LL |     let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
+   |                                    -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this
+   |                                    |
+   |                                    required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(TypeWithoutDeref) -> _`
+              found function signature `for<'a, 'b> fn(&'a &'b str) -> _`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0277, E0593, E0631.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.fixed b/tests/ui/mismatched_types/suggest-option-asderef.fixed
new file mode 100644
index 00000000000..08805999341
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+
+fn produces_string() -> Option<String> {
+    Some("my cool string".to_owned())
+}
+
+fn takes_str(_: &str) -> Option<()> {
+    Some(())
+}
+
+fn takes_str_mut(_: &mut str) -> Option<()> {
+    Some(())
+}
+
+fn generic<T>(_: T) -> Option<()> {
+    Some(())
+}
+
+fn main() {
+    let _: Option<()> = produces_string().as_deref().and_then(takes_str);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
+    let _: Option<Option<()>> = produces_string().as_deref().map(takes_str);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
+    let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref_mut()` first
+    let _ = produces_string().and_then(generic);
+}
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.rs b/tests/ui/mismatched_types/suggest-option-asderef.rs
new file mode 100644
index 00000000000..3cfb2ffa828
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef.rs
@@ -0,0 +1,30 @@
+// run-rustfix
+
+fn produces_string() -> Option<String> {
+    Some("my cool string".to_owned())
+}
+
+fn takes_str(_: &str) -> Option<()> {
+    Some(())
+}
+
+fn takes_str_mut(_: &mut str) -> Option<()> {
+    Some(())
+}
+
+fn generic<T>(_: T) -> Option<()> {
+    Some(())
+}
+
+fn main() {
+    let _: Option<()> = produces_string().and_then(takes_str);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
+    let _: Option<Option<()>> = produces_string().map(takes_str);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref()` first
+    let _: Option<Option<()>> = produces_string().map(takes_str_mut);
+    //~^ ERROR type mismatch in function arguments
+    //~| HELP call `Option::as_deref_mut()` first
+    let _ = produces_string().and_then(generic);
+}
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr
new file mode 100644
index 00000000000..46da19d2bf4
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr
@@ -0,0 +1,63 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef.rs:20:52
+   |
+LL | fn takes_str(_: &str) -> Option<()> {
+   | ----------------------------------- found signature defined here
+...
+LL |     let _: Option<()> = produces_string().and_then(takes_str);
+   |                                           -------- ^^^^^^^^^ expected due to this
+   |                                           |
+   |                                           required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a> fn(&'a str) -> _`
+note: required by a bound in `Option::<T>::and_then`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: call `Option::as_deref()` first
+   |
+LL |     let _: Option<()> = produces_string().as_deref().and_then(takes_str);
+   |                                          +++++++++++
+
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef.rs:23:55
+   |
+LL | fn takes_str(_: &str) -> Option<()> {
+   | ----------------------------------- found signature defined here
+...
+LL |     let _: Option<Option<()>> = produces_string().map(takes_str);
+   |                                                   --- ^^^^^^^^^ expected due to this
+   |                                                   |
+   |                                                   required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a> fn(&'a str) -> _`
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: call `Option::as_deref()` first
+   |
+LL |     let _: Option<Option<()>> = produces_string().as_deref().map(takes_str);
+   |                                                  +++++++++++
+
+error[E0631]: type mismatch in function arguments
+  --> $DIR/suggest-option-asderef.rs:26:55
+   |
+LL | fn takes_str_mut(_: &mut str) -> Option<()> {
+   | ------------------------------------------- found signature defined here
+...
+LL |     let _: Option<Option<()>> = produces_string().map(takes_str_mut);
+   |                                                   --- ^^^^^^^^^^^^^ expected due to this
+   |                                                   |
+   |                                                   required by a bound introduced by this call
+   |
+   = note: expected function signature `fn(String) -> _`
+              found function signature `for<'a> fn(&'a mut str) -> _`
+note: required by a bound in `Option::<T>::map`
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+help: call `Option::as_deref_mut()` first
+   |
+LL |     let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut);
+   |                                                  +++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.rs b/tests/ui/typeck/return-dyn-type-mismatch-2.rs
new file mode 100644
index 00000000000..328f154dcbc
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch-2.rs
@@ -0,0 +1,11 @@
+trait Trait<T> {}
+
+fn foo<T>() -> dyn Trait<T>
+where
+    dyn Trait<T>: Sized, // pesky sized predicate
+{
+    42
+    //~^ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/return-dyn-type-mismatch-2.stderr b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr
new file mode 100644
index 00000000000..9c368e83834
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch-2.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/return-dyn-type-mismatch-2.rs:7:5
+   |
+LL | fn foo<T>() -> dyn Trait<T>
+   |                ------------ expected `(dyn Trait<T> + 'static)` because of return type
+...
+LL |     42
+   |     ^^ expected `dyn Trait`, found integer
+   |
+   = note: expected trait object `(dyn Trait<T> + 'static)`
+                      found type `{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/return-dyn-type-mismatch.rs b/tests/ui/typeck/return-dyn-type-mismatch.rs
new file mode 100644
index 00000000000..93718f70f41
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch.rs
@@ -0,0 +1,21 @@
+pub trait TestTrait {
+    type MyType;
+
+    fn func() -> Option<Self>
+    where
+        Self: Sized;
+}
+
+impl<T> dyn TestTrait<MyType = T>
+where
+    Self: Sized, // pesky sized predicate
+{
+    fn other_func() -> dyn TestTrait<MyType = T> {
+        match Self::func() {
+            None => None,
+            //~^ ERROR mismatched types
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/return-dyn-type-mismatch.stderr b/tests/ui/typeck/return-dyn-type-mismatch.stderr
new file mode 100644
index 00000000000..9d0a609d87f
--- /dev/null
+++ b/tests/ui/typeck/return-dyn-type-mismatch.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/return-dyn-type-mismatch.rs:15:21
+   |
+LL |     fn other_func() -> dyn TestTrait<MyType = T> {
+   |                        ------------------------- expected `(dyn TestTrait<MyType = T> + 'static)` because of return type
+LL |         match Self::func() {
+LL |             None => None,
+   |                     ^^^^ expected `dyn TestTrait`, found `Option<_>`
+   |
+   = note: expected trait object `(dyn TestTrait<MyType = T> + 'static)`
+                      found enum `Option<_>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.