From 6ef203388483688b0a4598efbc63ee7295bff975 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Wed, 18 May 2022 03:51:52 +0100
Subject: [PATCH 01/21] Fix FFI-unwind unsoundness with mixed panic mode

---
 compiler/rustc_interface/src/passes.rs        |   1 +
 compiler/rustc_lint_defs/src/builtin.rs       |  40 +++++
 compiler/rustc_metadata/src/creader.rs        |   2 +-
 .../rustc_metadata/src/dependency_format.rs   |  11 +-
 compiler/rustc_metadata/src/rmeta/decoder.rs  |   2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs  |   2 +-
 compiler/rustc_metadata/src/rmeta/mod.rs      |   2 +-
 compiler/rustc_middle/src/query/mod.rs        |  11 +-
 .../src/ffi_unwind_calls.rs                   | 148 ++++++++++++++++++
 compiler/rustc_mir_transform/src/lib.rs       |   5 +
 library/std/src/lib.rs                        |   2 +
 11 files changed, 212 insertions(+), 14 deletions(-)
 create mode 100644 compiler/rustc_mir_transform/src/ffi_unwind_calls.rs

diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 3c867e308c40e..ef9c7859dbb7a 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -944,6 +944,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_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a067534b18938..48d89a785c117 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3230,6 +3230,7 @@ declare_lint_pass! {
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         TEST_UNSTABLE_LINT,
+        FFI_UNWIND_CALLS,
     ]
 }
 
@@ -3895,3 +3896,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 947d563ae3cd1..3f6d1f050056d 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -744,7 +744,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.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..349ff08124cf6 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,7 +366,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                     prev_name, cur_name
                 ));
             }
-            panic_runtime = Some((cnum, tcx.panic_strategy(cnum)));
+            panic_runtime = Some((cnum, tcx.panic_strategy(cnum).unwrap()));
         }
     }
 
@@ -397,18 +396,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) {
                 continue;
             }
 
-            let found_strategy = tcx.panic_strategy(cnum);
-            if desired_strategy != found_strategy {
+            if let Some(found_strategy) = tcx.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 03ac82b467b8e..658c51bf62043 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1759,7 +1759,7 @@ impl CrateMetadata {
         self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
     }
 
-    pub(crate) fn panic_strategy(&self) -> PanicStrategy {
+    pub(crate) fn panic_strategy(&self) -> Option<PanicStrategy> {
         self.root.panic_strategy
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 8867e008e42fa..cf685a7bd6217 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(),
+            panic_strategy: tcx.required_panic_strategy(()),
             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 04f0847f5cccc..60510e535b244 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,
+    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 5b48f164016f7..5d0d11a1b784a 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1365,9 +1365,16 @@ 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(_: ()) -> Option<PanicStrategy> {
+        desc { "compute the required panic strategy for the current crate" }
+    }
+    query 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/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
new file mode 100644
index 0000000000000..e6f8ef5759a11
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -0,0 +1,148 @@
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
+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);
+    let is_function = match kind {
+        DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+        _ => tcx.is_closure(def_id),
+    };
+    if !is_function {
+        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<'_>, (): ()) -> Option<PanicStrategy> {
+    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) {
+            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 0e57c3c697999..e4591c3f23e71 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -57,6 +57,7 @@ mod dest_prop;
 pub mod dump_mir;
 mod early_otherwise_branch;
 mod elaborate_drops;
+mod ffi_unwind_calls;
 mod function_item_references;
 mod generator;
 mod inline;
@@ -96,6 +97,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,
@@ -221,6 +223,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/library/std/src/lib.rs b/library/std/src/lib.rs
index b1c68ec43bc99..fc2ff3635133c 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))]

From 77fd0cc566b4eca108b3580312f1e298fc9af8df Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Thu, 19 May 2022 17:38:54 +0100
Subject: [PATCH 02/21] Handle panic runtime specially

---
 compiler/rustc_metadata/src/dependency_format.rs    | 13 +++++++++----
 .../rustc_mir_transform/src/ffi_unwind_calls.rs     |  6 +++++-
 .../ui/panic-runtime/transitive-link-a-bunch.stderr |  6 ++----
 src/test/ui/panic-runtime/want-unwind-got-abort.rs  |  2 +-
 .../ui/panic-runtime/want-unwind-got-abort.stderr   |  4 +---
 .../ui/panic-runtime/want-unwind-got-abort2.stderr  |  6 ++----
 6 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 349ff08124cf6..e22c903bf336e 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -366,14 +366,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                     prev_name, cur_name
                 ));
             }
-            panic_runtime = Some((cnum, tcx.panic_strategy(cnum).unwrap()));
+            panic_runtime = Some((
+                cnum,
+                tcx.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
@@ -383,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,7 +402,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                 continue;
             }
             let cnum = CrateNum::new(i + 1);
-            if tcx.is_compiler_builtins(cnum) {
+            if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
                 continue;
             }
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index e6f8ef5759a11..78809b105359d 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,5 +1,5 @@
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::query::Providers;
@@ -129,6 +129,10 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
 }
 
 fn required_panic_strategy(tcx: TyCtxt<'_>, (): ()) -> Option<PanicStrategy> {
+    if tcx.is_panic_runtime(LOCAL_CRATE) {
+        return Some(tcx.sess.panic_strategy());
+    }
+
     if tcx.sess.panic_strategy() == PanicStrategy::Abort {
         return Some(PanicStrategy::Abort);
     }
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
 

From bc5afd9e347c79d7e0c910eb4f452410579ca4b6 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Thu, 19 May 2022 23:37:26 +0100
Subject: [PATCH 03/21] Ensure ffi_unwind_calls lint is gated behind c_unwind

---
 .../ui/unwind-abis/feature-gate-c-unwind.rs   |  4 +++
 .../unwind-abis/feature-gate-c-unwind.stderr  | 25 +++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

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`.

From 1750a2f723a796b9c98b223df6013f3b1b0254df Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Fri, 20 May 2022 21:52:00 +0100
Subject: [PATCH 04/21] Add tests for mixed panic mode restriction and lints

---
 .../ui/panic-runtime/auxiliary/needs-abort.rs |  5 ++++
 .../panic-runtime/auxiliary/needs-unwind.rs   | 13 ++++++++++
 .../ui/panic-runtime/need-abort-got-unwind.rs |  9 +++++++
 .../need-abort-got-unwind.stderr              |  4 +++
 .../ui/panic-runtime/need-unwind-got-abort.rs |  8 ++++++
 .../need-unwind-got-abort.stderr              |  6 +++++
 .../ui/unwind-abis/ffi-unwind-calls-lint.rs   | 25 +++++++++++++++++++
 .../unwind-abis/ffi-unwind-calls-lint.stderr  | 20 +++++++++++++++
 8 files changed, 90 insertions(+)
 create mode 100644 src/test/ui/panic-runtime/auxiliary/needs-abort.rs
 create mode 100644 src/test/ui/panic-runtime/auxiliary/needs-unwind.rs
 create mode 100644 src/test/ui/panic-runtime/need-abort-got-unwind.rs
 create mode 100644 src/test/ui/panic-runtime/need-abort-got-unwind.stderr
 create mode 100644 src/test/ui/panic-runtime/need-unwind-got-abort.rs
 create mode 100644 src/test/ui/panic-runtime/need-unwind-got-abort.stderr
 create mode 100644 src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs
 create mode 100644 src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr

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..3bcc0aa39ac96
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
@@ -0,0 +1,8 @@
+// build-fail
+// error-pattern:is incompatible with this crate's strategy of `abort`
+// aux-build:needs-unwind.rs
+// compile-flags:-C panic=abort
+
+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..a53b7ffe57485
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
@@ -0,0 +1,6 @@
+error: the linked panic runtime `panic_unwind` is not compiled with this crate's panic strategy `abort`
+
+error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`
+
+error: aborting due to 2 previous errors
+
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
+

From 9e6c044ee6860d8b97324c75cf3dfd6f47e2488e Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Mon, 23 May 2022 21:30:38 +0100
Subject: [PATCH 05/21] Use is_fn_like instead of matching on DefKind

---
 compiler/rustc_mir_transform/src/abort_unwinding_calls.rs | 7 +------
 compiler/rustc_mir_transform/src/ffi_unwind_calls.rs      | 7 +------
 2 files changed, 2 insertions(+), 12 deletions(-)

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
index 78809b105359d..b8ef68f608cc3 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,4 +1,3 @@
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
@@ -44,11 +43,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     // 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);
-    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 false;
     }
 

From 14d155a3dc42b35856e45fd9f4212ac0c432cd10 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Wed, 8 Jun 2022 21:32:17 +0100
Subject: [PATCH 06/21] Rename `panic_strategy` query to
 `required_panic_strategy`

---
 compiler/rustc_metadata/src/creader.rs                   | 2 +-
 compiler/rustc_metadata/src/dependency_format.rs         | 4 ++--
 compiler/rustc_metadata/src/rmeta/decoder.rs             | 4 ++--
 compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs             | 2 +-
 compiler/rustc_metadata/src/rmeta/mod.rs                 | 2 +-
 compiler/rustc_middle/src/query/mod.rs                   | 5 +----
 compiler/rustc_mir_transform/src/ffi_unwind_calls.rs     | 6 ++++--
 8 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 3f6d1f050056d..907324f0e4fc4 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -744,7 +744,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() != Some(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 e22c903bf336e..770d164894a73 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -368,7 +368,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             }
             panic_runtime = Some((
                 cnum,
-                tcx.panic_strategy(cnum).unwrap_or_else(|| {
+                tcx.required_panic_strategy(cnum).unwrap_or_else(|| {
                     bug!("cannot determine panic strategy of a panic runtime");
                 }),
             ));
@@ -406,7 +406,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                 continue;
             }
 
-            if let Some(found_strategy) = tcx.panic_strategy(cnum) && desired_strategy != found_strategy {
+            if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy {
                 sess.err(&format!(
                     "the crate `{}` requires \
                                panic strategy `{}` which is \
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 658c51bf62043..b8efca19fb28b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1759,8 +1759,8 @@ impl CrateMetadata {
         self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
     }
 
-    pub(crate) fn panic_strategy(&self) -> Option<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 e3581a7607fb8..1237ac4ec4780 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 cf685a7bd6217..12cc5a72aa736 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.required_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 60510e535b244..900d9b9842631 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: Option<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 5d0d11a1b784a..bcf7497b832b4 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1369,10 +1369,7 @@ rustc_queries! {
         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(_: ()) -> Option<PanicStrategy> {
-        desc { "compute the required panic strategy for the current crate" }
-    }
-    query panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
+    query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
         fatal_cycle
         desc { "query a crate's required panic strategy" }
         separate_provide_extern
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index b8ef68f608cc3..d09d2a0b26346 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,4 +1,4 @@
-use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::query::Providers;
@@ -123,7 +123,9 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     tainted
 }
 
-fn required_panic_strategy(tcx: TyCtxt<'_>, (): ()) -> Option<PanicStrategy> {
+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());
     }

From ce774e377881671b968d193440d99884e84039b6 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Wed, 8 Jun 2022 22:42:05 +0100
Subject: [PATCH 07/21] Add a explanation about required panic strategy
 computation

---
 .../src/ffi_unwind_calls.rs                   | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index d09d2a0b26346..7728fdaffb0dc 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -136,6 +136,27 @@ fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrat
 
     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);
         }
     }

From dcfe92e193eb0d3d9df455f3274d6ba2d90c45c1 Mon Sep 17 00:00:00 2001
From: leocth <leocth31@gmail.com>
Date: Sat, 25 Jun 2022 11:19:08 +0800
Subject: [PATCH 08/21] add `fetch_not` method on `AtomicBool`

---
 library/core/src/sync/atomic.rs | 35 +++++++++++++++++++++++++++++++++
 library/core/tests/atomic.rs    | 14 +++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index a66ecc35bbdb1..afc4eda49abd5 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -854,6 +854,41 @@ impl AtomicBool {
         unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
     }
 
+    /// Logical "not" with a boolean value.
+    ///
+    /// Performs a logical "not" operation on the current value, and sets
+    /// the new value to the result.
+    ///
+    /// Returns the previous value.
+    ///
+    /// `fetch_not` takes an [`Ordering`] argument which describes the memory ordering
+    /// of this operation. All ordering modes are possible. Note that using
+    /// [`Acquire`] makes the store part of this operation [`Relaxed`], and
+    /// using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note:** This method is only available on platforms that support atomic
+    /// operations on `u8`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// let foo = AtomicBool::new(true);
+    /// assert_eq!(foo.fetch_not(Ordering::SeqCst), true);
+    /// assert_eq!(foo.load(Ordering::SeqCst), false);
+    ///
+    /// let foo = AtomicBool::new(false);
+    /// assert_eq!(foo.fetch_not(Ordering::SeqCst), false);
+    /// assert_eq!(foo.load(Ordering::SeqCst), true);
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(target_has_atomic = "8")]
+    pub fn fetch_not(&self, order: Ordering) -> bool {
+        self.fetch_xor(true, order)
+    }
+
     /// Returns a mutable pointer to the underlying [`bool`].
     ///
     /// Doing non-atomic reads and writes on the resulting integer can be a data race.
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 7f8672f035417..36d1929d5be46 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -30,6 +30,18 @@ fn bool_nand() {
     assert_eq!(a.fetch_nand(true, SeqCst), false);
     assert_eq!(a.load(SeqCst), true);
 }
+#[test]
+fn bool_not() {
+    let a = AtomicBool::new(false);
+    assert_eq!(a.fetch_not(SeqCst), false);
+    assert_eq!(a.load(SeqCst), true);
+    assert_eq!(a.fetch_not(SeqCst), true);
+    assert_eq!(a.load(SeqCst), false);
+    assert_eq!(a.fetch_not(SeqCst), false);
+    assert_eq!(a.load(SeqCst), true);
+    assert_eq!(a.fetch_not(SeqCst), true);
+    assert_eq!(a.load(SeqCst), false);
+}
 
 #[test]
 fn uint_and() {
@@ -158,6 +170,8 @@ fn atomic_access_bool() {
         assert_eq!(*ATOMIC.get_mut(), true);
         ATOMIC.fetch_xor(true, SeqCst);
         assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.fetch_not(SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
     }
 }
 

From 7d5f236c3d6c1f7e74bcb6c1cd4f87ea65f7295a Mon Sep 17 00:00:00 2001
From: leocth <leocth31@gmail.com>
Date: Sat, 25 Jun 2022 18:18:58 +0800
Subject: [PATCH 09/21] Add feature gate `#![atomic_bool_fetch_not]`

---
 library/core/src/sync/atomic.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index afc4eda49abd5..92afdab299948 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -883,7 +883,7 @@ impl AtomicBool {
     /// assert_eq!(foo.load(Ordering::SeqCst), true);
     /// ```
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
+    #[unstable(feature = "atomic_bool_fetch_not", issue = "98485")]
     #[cfg(target_has_atomic = "8")]
     pub fn fetch_not(&self, order: Ordering) -> bool {
         self.fetch_xor(true, order)

From 0df7364cdf7adf2b9446395c01915d377a4155ec Mon Sep 17 00:00:00 2001
From: leocth <leocth31@gmail.com>
Date: Sun, 26 Jun 2022 00:06:50 +0800
Subject: [PATCH 10/21] temporarily remove tests because I'm not sure if we
 need them

---
 library/core/tests/atomic.rs | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 36d1929d5be46..7f8672f035417 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -30,18 +30,6 @@ fn bool_nand() {
     assert_eq!(a.fetch_nand(true, SeqCst), false);
     assert_eq!(a.load(SeqCst), true);
 }
-#[test]
-fn bool_not() {
-    let a = AtomicBool::new(false);
-    assert_eq!(a.fetch_not(SeqCst), false);
-    assert_eq!(a.load(SeqCst), true);
-    assert_eq!(a.fetch_not(SeqCst), true);
-    assert_eq!(a.load(SeqCst), false);
-    assert_eq!(a.fetch_not(SeqCst), false);
-    assert_eq!(a.load(SeqCst), true);
-    assert_eq!(a.fetch_not(SeqCst), true);
-    assert_eq!(a.load(SeqCst), false);
-}
 
 #[test]
 fn uint_and() {
@@ -170,8 +158,6 @@ fn atomic_access_bool() {
         assert_eq!(*ATOMIC.get_mut(), true);
         ATOMIC.fetch_xor(true, SeqCst);
         assert_eq!(*ATOMIC.get_mut(), false);
-        ATOMIC.fetch_not(SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
     }
 }
 

From 9c5ae20c5952824614a3d2c67a467f2c0d0d9d86 Mon Sep 17 00:00:00 2001
From: leocth <leocth31@gmail.com>
Date: Sun, 26 Jun 2022 10:48:17 +0800
Subject: [PATCH 11/21] forgot about the feature flag in the doctest

---
 library/core/src/sync/atomic.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 92afdab299948..b974b431b780d 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -872,6 +872,7 @@ impl AtomicBool {
     /// # Examples
     ///
     /// ```
+    /// #![feature(atomic_bool_fetch_not)]
     /// use std::sync::atomic::{AtomicBool, Ordering};
     ///
     /// let foo = AtomicBool::new(true);

From 6e32a165208242153af66a12cbe4448b05525f82 Mon Sep 17 00:00:00 2001
From: DrMeepster <19316085+DrMeepster@users.noreply.github.com>
Date: Sun, 26 Jun 2022 13:58:37 -0700
Subject: [PATCH 12/21] fix box with custom allocator in miri

---
 compiler/rustc_const_eval/src/interpret/cast.rs  | 16 ----------------
 .../rustc_const_eval/src/interpret/validity.rs   |  5 ++++-
 2 files changed, 4 insertions(+), 17 deletions(-)

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..3809030b51560 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -594,7 +594,10 @@ 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")?;
                 Ok(true)
             }
             ty::FnPtr(_sig) => {

From d317988505cade110cc8c9f1d03e6a98622f10bd Mon Sep 17 00:00:00 2001
From: DrMeepster <19316085+DrMeepster@users.noreply.github.com>
Date: Sun, 26 Jun 2022 18:54:03 -0700
Subject: [PATCH 13/21] validate box's allocator

---
 compiler/rustc_const_eval/src/interpret/validity.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 3809030b51560..00e4472721f3f 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -598,6 +598,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 let nonnull = self.ecx.operand_field(&unique, 0)?;
                 let ptr = self.ecx.operand_field(&nonnull, 0)?;
                 self.check_safe_pointer(&ptr, "box")?;
+
+                let allocator = self.ecx.operand_field(value, 1)?;
+                self.visit_field(value, 1, &allocator)?;
                 Ok(true)
             }
             ty::FnPtr(_sig) => {

From 75337775f776250a3a29c951344186e698c11c75 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 28 Jun 2022 00:12:49 -0700
Subject: [PATCH 14/21] Remove `final_arg_types`, improve tuple wrapping
 suggestion

---
 .../src/infer/error_reporting/mod.rs          |   4 +-
 .../rustc_typeck/src/check/fn_ctxt/checks.rs  | 310 ++++++++----------
 .../suggestions/args-instead-of-tuple.stderr  |  10 +-
 .../ui/tuple/add-tuple-within-arguments.rs    |  10 +
 .../tuple/add-tuple-within-arguments.stderr   |  40 +++
 src/test/ui/tuple/wrong_argument_ice-2.stderr |   2 +-
 src/test/ui/tuple/wrong_argument_ice.stderr   |   2 +-
 7 files changed, 199 insertions(+), 179 deletions(-)
 create mode 100644 src/test/ui/tuple/add-tuple-within-arguments.rs
 create mode 100644 src/test/ui/tuple/add-tuple-within-arguments.stderr

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b94d205488d01..e319f17b0e60d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -342,8 +342,8 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
         )
         | (&ty::Infer(ty::InferTy::TyVar(_)), _)
         | (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
-        (&ty::Ref(reg_a, ty_a, mut_a), &ty::Ref(reg_b, ty_b, mut_b)) => {
-            reg_a == reg_b && mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
+        (&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
+            mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
         }
         _ => a == b,
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 08df01c0c1a1a..ede2ed5169f80 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -24,7 +24,6 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
 use rustc_session::Session;
@@ -35,12 +34,6 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpres
 use std::iter;
 use std::slice;
 
-enum TupleMatchFound {
-    None,
-    Single,
-    /// Beginning and end Span
-    Multiple(Span, Span),
-}
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&self) {
         let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -216,14 +209,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let minimum_input_count = expected_input_tys.len();
         let provided_arg_count = provided_args.len();
 
-        // We'll also want to keep track of the fully coerced argument types, for an awkward hack near the end
-        // FIXME(compiler-errors): Get rid of this, actually.
-        let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count];
-
         // We introduce a helper function to demand that a given argument satisfy a given input
         // This is more complicated than just checking type equality, as arguments could be coerced
         // This version writes those types back so further type checking uses the narrowed types
-        let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
+        let demand_compatible = |idx| {
             let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
             let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
             let provided_arg = &provided_args[idx];
@@ -242,9 +231,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
             let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
 
-            // Keep track of these for below
-            final_arg_types[idx] = Some((checked_ty, coerced_ty));
-
             // Cause selection errors caused by resolving a single argument to point at the
             // argument and not the call. This lets us customize the span pointed to in the
             // fulfillment error to be more accurate.
@@ -253,16 +239,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
-                        &final_arg_types,
                         call_expr,
                         call_span,
                         provided_args,
+                        &expected_input_tys,
                     );
                 });
 
-            // Make sure we store the resolved type
-            final_arg_types[idx] = Some((checked_ty, coerced_ty));
-
             let coerce_error = self
                 .try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None)
                 .err();
@@ -320,10 +303,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
-                        &final_arg_types,
                         call_expr,
                         call_span,
                         &provided_args,
+                        &expected_input_tys,
                     );
                 })
             }
@@ -352,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     continue;
                 }
 
-                let compatible = demand_compatible(idx, &mut final_arg_types);
+                let compatible = demand_compatible(idx);
                 let is_compatible = matches!(compatible, Compatibility::Compatible);
                 compatibility_diagonal[idx] = compatible;
 
@@ -445,72 +428,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 None => "function",
             };
 
-            let try_tuple_wrap_args = || {
-                // The case where we expect a single tuple and wrapping all the args
-                // in parentheses (or adding a comma to already existing parentheses)
-                // will result in a tuple that satisfies the call.
-                // This isn't super ideal code, because we copy code from elsewhere
-                // and somewhat duplicate this. We also delegate to the general type
-                // mismatch suggestions for the single arg case.
-                match self.suggested_tuple_wrap(&expected_input_tys, provided_args) {
-                    TupleMatchFound::Single => {
-                        let expected_ty = expected_input_tys[0];
-                        let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
-                        let expected_ty = self.resolve_vars_if_possible(expected_ty);
-                        let provided_ty = self.resolve_vars_if_possible(provided_ty);
-                        let cause = &self.misc(provided_args[0].span);
-                        let compatibility = demand_compatible(0, &mut final_arg_types);
-                        let type_error = match compatibility {
-                            Compatibility::Incompatible(Some(error)) => error,
-                            _ => TypeError::Mismatch,
-                        };
-                        let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
-                        let mut err = self.report_and_explain_type_error(trace, &type_error);
-                        self.emit_coerce_suggestions(
-                            &mut err,
-                            &provided_args[0],
-                            final_arg_types[0].map(|ty| ty.0).unwrap(),
-                            final_arg_types[0].map(|ty| ty.1).unwrap(),
-                            None,
-                            None,
-                        );
-                        err.span_label(
-                            full_call_span,
-                            format!("arguments to this {} are incorrect", call_name),
-                        );
-                        // Call out where the function is defined
-                        label_fn_like(tcx, &mut err, fn_def_id);
-                        err.emit();
-                        return true;
-                    }
-                    TupleMatchFound::Multiple(start, end) => {
-                        let mut err = tcx.sess.struct_span_err_with_code(
-                            full_call_span,
-                            &format!(
-                                "this {} takes {}{} but {} {} supplied",
-                                call_name,
-                                if c_variadic { "at least " } else { "" },
-                                potentially_plural_count(minimum_input_count, "argument"),
-                                potentially_plural_count(provided_arg_count, "argument"),
-                                if provided_arg_count == 1 { "was" } else { "were" }
-                            ),
-                            DiagnosticId::Error(err_code.to_owned()),
-                        );
-                        // Call out where the function is defined
-                        label_fn_like(tcx, &mut err, fn_def_id);
-                        err.multipart_suggestion(
-                            "use parentheses to construct a tuple",
-                            vec![(start, '('.to_string()), (end, ')'.to_string())],
-                            Applicability::MachineApplicable,
-                        );
-                        err.emit();
-                        return true;
-                    }
-                    TupleMatchFound::None => {}
-                }
-                false
-            };
-
             let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
             let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
                 minimum_input_count
@@ -541,7 +458,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 c_variadic,
                 err_code,
                 fn_def_id,
-                try_tuple_wrap_args,
             );
         }
     }
@@ -558,7 +474,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         c_variadic: bool,
         err_code: &str,
         fn_def_id: Option<DefId>,
-        try_tuple_wrap_args: impl FnOnce() -> bool,
     ) {
         // Don't print if it has error types or is just plain `_`
         fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
@@ -578,7 +493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx];
             // If either is an error type, we defy the usual convention and consider them to *not* be
-            // coercible.  This prevents our error message heuristic from trying to pass errors into
+            // coercible. This prevents our error message heuristic from trying to pass errors into
             // every argument.
             if (formal_input_ty, expected_input_ty).references_error() {
                 return Compatibility::Incompatible(None);
@@ -599,16 +514,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return Compatibility::Incompatible(None);
             }
 
-            let subtyping_result = self
-                .at(&self.misc(provided_arg.span), self.param_env)
-                .sup(formal_input_ty, coerced_ty);
+            // Using probe here, since we don't want this subtyping to affect inference.
+            let subtyping_error = self.probe(|_| {
+                self.at(&self.misc(provided_arg.span), self.param_env)
+                    .sup(formal_input_ty, coerced_ty)
+                    .err()
+            });
 
             // Same as above: if either the coerce type or the checked type is an error type,
             // consider them *not* compatible.
             let references_error = (coerced_ty, checked_ty).references_error();
-            match (references_error, &subtyping_result) {
-                (false, Ok(_)) => Compatibility::Compatible,
-                _ => Compatibility::Incompatible(subtyping_result.err()),
+            match (references_error, subtyping_error) {
+                (false, None) => Compatibility::Compatible,
+                (_, subtyping_error) => Compatibility::Incompatible(subtyping_error),
             }
         };
 
@@ -629,9 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .iter()
             .map(|expr| {
                 let ty = self
-                    .in_progress_typeck_results
-                    .as_ref()
-                    .unwrap()
+                    .typeck_results
                     .borrow()
                     .expr_ty_adjusted_opt(*expr)
                     .unwrap_or_else(|| tcx.ty_error());
@@ -639,6 +555,97 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             .collect();
 
+        // First, check if we just need to wrap some arguments in a tuple.
+        if let Some((mismatch_idx, terr)) =
+            compatibility_diagonal.iter().enumerate().find_map(|(i, c)| {
+                if let Compatibility::Incompatible(Some(terr)) = c { Some((i, terr)) } else { None }
+            })
+        {
+            // Is the first bad expected argument a tuple?
+            // Do we have as many extra provided arguments as the tuple's length?
+            // If so, we might have just forgotten to wrap some args in a tuple.
+            if let Some(ty::Tuple(tys)) =
+                formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+                && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
+            {
+                // Wrap up the N provided arguments starting at this position in a tuple.
+                let provided_as_tuple = tcx.mk_tup(
+                    provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
+                );
+
+                let mut satisfied = true;
+                // Check if the newly wrapped tuple + rest of the arguments are compatible.
+                for ((_, expected_ty), provided_ty) in std::iter::zip(
+                    formal_and_expected_inputs.iter().skip(mismatch_idx),
+                    [provided_as_tuple].into_iter().chain(
+                        provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
+                    ),
+                ) {
+                    if !self.can_coerce(provided_ty, *expected_ty) {
+                        satisfied = false;
+                        break;
+                    }
+                }
+
+                // If they're compatible, suggest wrapping in an arg, and we're done!
+                // Take some care with spans, so we don't suggest wrapping a macro's
+                // innards in parenthesis, for example.
+                if satisfied
+                    && let Some(lo) =
+                        provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span)
+                    && let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()]
+                        .span
+                        .find_ancestor_inside(error_span)
+                {
+                    let mut err;
+                    if tys.len() == 1 {
+                        // A tuple wrap suggestion actually occurs within,
+                        // so don't do anything special here.
+                        err = self.report_and_explain_type_error(
+                            TypeTrace::types(
+                                &self.misc(lo),
+                                true,
+                                formal_and_expected_inputs[mismatch_idx.into()].1,
+                                provided_arg_tys[mismatch_idx.into()].0,
+                            ),
+                            terr,
+                        );
+                        err.span_label(
+                            full_call_span,
+                            format!("arguments to this {} are incorrect", call_name),
+                        );
+                    } else {
+                        err = tcx.sess.struct_span_err_with_code(
+                            full_call_span,
+                            &format!(
+                                "this {} takes {}{} but {} {} supplied",
+                                call_name,
+                                if c_variadic { "at least " } else { "" },
+                                potentially_plural_count(
+                                    formal_and_expected_inputs.len(),
+                                    "argument"
+                                ),
+                                potentially_plural_count(provided_args.len(), "argument"),
+                                if provided_args.len() == 1 { "was" } else { "were" }
+                            ),
+                            DiagnosticId::Error(err_code.to_owned()),
+                        );
+                        err.multipart_suggestion_verbose(
+                            "wrap these arguments in parentheses to construct a tuple",
+                            vec![
+                                (lo.shrink_to_lo(), "(".to_string()),
+                                (hi.shrink_to_hi(), ")".to_string()),
+                            ],
+                            Applicability::MachineApplicable,
+                        );
+                    };
+                    label_fn_like(tcx, &mut err, fn_def_id);
+                    err.emit();
+                    return;
+                }
+            }
+        }
+
         // Okay, so here's where it gets complicated in regards to what errors
         // we emit and how.
         // There are 3 different "types" of errors we might encounter.
@@ -666,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                     .note(
                         "we would appreciate a bug report: \
-                        https://github.com/rust-lang/rust-clippy/issues/new",
+                        https://github.com/rust-lang/rust/issues/new",
                     )
                     .emit();
             }
@@ -727,13 +734,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        // Second, let's try tuple wrapping the args.
-        // FIXME(compiler-errors): This is currently in its own closure because
-        // I didn't want to factor it out.
-        if try_tuple_wrap_args() {
-            return;
-        }
-
         let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
             struct_span_err!(
                 tcx.sess,
@@ -989,13 +989,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else {
                             String::new()
                         };
-                        // FIXME(compiler-errors): Why do we get permutations with the same type?
-                        if expected_ty != provided_ty {
-                            labels.push((
-                                provided_span,
-                                format!("expected `{}`{}", expected_ty, provided_ty_name),
-                            ));
-                        }
+                        labels.push((
+                            provided_span,
+                            format!("expected `{}`{}", expected_ty, provided_ty_name),
+                        ));
                     }
 
                     suggestion_text = match suggestion_text {
@@ -1043,10 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     needs_comma = true;
                 }
-                let suggestion_text =
-                    if let Some(provided_idx) = provided_idx
+                let suggestion_text = if let Some(provided_idx) = provided_idx
                     && let (_, provided_span) = provided_arg_tys[*provided_idx]
-                    && let Ok(arg_text) = source_map.span_to_snippet(provided_span.source_callsite()) {
+                    && let Ok(arg_text) =
+                        source_map.span_to_snippet(provided_span.source_callsite())
+                {
                     arg_text
                 } else {
                     // Propose a placeholder of the correct type
@@ -1073,38 +1071,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit();
     }
 
-    fn suggested_tuple_wrap(
-        &self,
-        expected_input_tys: &[Ty<'tcx>],
-        provided_args: &'tcx [hir::Expr<'tcx>],
-    ) -> TupleMatchFound {
-        // Only handle the case where we expect only one tuple arg
-        let [expected_arg_type] = expected_input_tys[..] else { return TupleMatchFound::None };
-        let &ty::Tuple(expected_types) = self.resolve_vars_if_possible(expected_arg_type).kind()
-            else { return TupleMatchFound::None };
-
-        // First check that there are the same number of types.
-        if expected_types.len() != provided_args.len() {
-            return TupleMatchFound::None;
-        }
-
-        let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
-
-        let all_match = iter::zip(expected_types, supplied_types)
-            .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok());
-
-        if !all_match {
-            return TupleMatchFound::None;
-        }
-        match provided_args {
-            [] => TupleMatchFound::None,
-            [_] => TupleMatchFound::Single,
-            [first, .., last] => {
-                TupleMatchFound::Multiple(first.span.shrink_to_lo(), last.span.shrink_to_hi())
-            }
-        }
-    }
-
     // AST fragment checking
     pub(in super::super) fn check_lit(
         &self,
@@ -1652,10 +1618,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn point_at_arg_instead_of_call_if_possible(
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>],
         expr: &'tcx hir::Expr<'tcx>,
         call_sp: Span,
         args: &'tcx [hir::Expr<'tcx>],
+        expected_tys: &[Ty<'tcx>],
     ) {
         // We *do not* do this for desugared call spans to keep good diagnostics when involving
         // the `?` operator.
@@ -1688,39 +1654,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (result_code, code) = (code, parent);
                 }
             }
-            let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) {
-                ObligationCauseCode::BuiltinDerivedObligation(code) |
-                ObligationCauseCode::DerivedObligation(code) => {
-                    code.parent_trait_pred.self_ty().skip_binder().into()
-                }
-                ObligationCauseCode::ImplDerivedObligation(code) => {
-                    code.derived.parent_trait_pred.self_ty().skip_binder().into()
-                }
-                _ if let ty::PredicateKind::Trait(predicate) =
-                    error.obligation.predicate.kind().skip_binder() => {
+            let self_: ty::subst::GenericArg<'_> =
+                match unpeel_to_top(error.obligation.cause.code()) {
+                    ObligationCauseCode::BuiltinDerivedObligation(code)
+                    | ObligationCauseCode::DerivedObligation(code) => {
+                        code.parent_trait_pred.self_ty().skip_binder().into()
+                    }
+                    ObligationCauseCode::ImplDerivedObligation(code) => {
+                        code.derived.parent_trait_pred.self_ty().skip_binder().into()
+                    }
+                    _ if let ty::PredicateKind::Trait(predicate) =
+                        error.obligation.predicate.kind().skip_binder() =>
+                    {
                         predicate.self_ty().into()
                     }
-                _ =>  continue,
-            };
+                    _ => continue,
+                };
             let self_ = self.resolve_vars_if_possible(self_);
 
             // Collect the argument position for all arguments that could have caused this
             // `FulfillmentError`.
-            let mut referenced_in = final_arg_types
-                .iter()
+            let typeck_results = self.typeck_results.borrow();
+            let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args)
                 .enumerate()
-                .filter_map(|(i, arg)| match arg {
-                    Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]),
-                    _ => None,
+                .flat_map(|(idx, (expected_ty, arg))| {
+                    if let Some(arg_ty) = typeck_results.expr_ty_opt(arg) {
+                        vec![(idx, arg_ty), (idx, *expected_ty)]
+                    } else {
+                        vec![]
+                    }
                 })
-                .flatten()
-                .flat_map(|(i, ty)| {
+                .filter_map(|(i, ty)| {
                     let ty = self.resolve_vars_if_possible(ty);
                     // We walk the argument type because the argument's type could have
                     // been `Option<T>`, but the `FulfillmentError` references `T`.
                     if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
                 })
-                .collect::<Vec<usize>>();
+                .collect();
 
             // Both checked and coerced types could have matched, thus we need to remove
             // duplicates.
diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr
index f6d158782dad2..2448a5149654d 100644
--- a/src/test/ui/suggestions/args-instead-of-tuple.stderr
+++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr
@@ -9,7 +9,7 @@ note: tuple variant defined here
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |     let _: Result<(i32, i8), ()> = Ok((1, 2));
    |                                       +    +
@@ -25,7 +25,7 @@ note: tuple variant defined here
    |
 LL |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |     let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
    |                                                   +          +
@@ -97,7 +97,7 @@ note: function defined here
    |
 LL | fn two_ints(_: (i32, i32)) {
    |    ^^^^^^^^ -------------
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |     two_ints((1, 2));
    |              +    +
@@ -113,7 +113,7 @@ note: function defined here
    |
 LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
    |    ^^^^^^^^^^^^                 ----------------
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |     with_generic((3, 4));
    |                  +    +
@@ -129,7 +129,7 @@ note: function defined here
    |
 LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
    |    ^^^^^^^^^^^^                 ----------------
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |         with_generic((a, b));
    |                      +    +
diff --git a/src/test/ui/tuple/add-tuple-within-arguments.rs b/src/test/ui/tuple/add-tuple-within-arguments.rs
new file mode 100644
index 0000000000000..089c703fda5c7
--- /dev/null
+++ b/src/test/ui/tuple/add-tuple-within-arguments.rs
@@ -0,0 +1,10 @@
+fn foo(s: &str, a: (i32, i32), s2: &str) {}
+
+fn bar(s: &str, a: (&str,), s2: &str) {}
+
+fn main() {
+    foo("hi", 1, 2, "hi");
+    //~^ ERROR this function takes 3 arguments but 4 arguments were supplied
+    bar("hi", "hi", "hi");
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/tuple/add-tuple-within-arguments.stderr b/src/test/ui/tuple/add-tuple-within-arguments.stderr
new file mode 100644
index 0000000000000..95df96ca0dd4f
--- /dev/null
+++ b/src/test/ui/tuple/add-tuple-within-arguments.stderr
@@ -0,0 +1,40 @@
+error[E0061]: this function takes 3 arguments but 4 arguments were supplied
+  --> $DIR/add-tuple-within-arguments.rs:6:5
+   |
+LL |     foo("hi", 1, 2, "hi");
+   |     ^^^
+   |
+note: function defined here
+  --> $DIR/add-tuple-within-arguments.rs:1:4
+   |
+LL | fn foo(s: &str, a: (i32, i32), s2: &str) {}
+   |    ^^^ -------  -------------  --------
+help: wrap these arguments in parentheses to construct a tuple
+   |
+LL |     foo("hi", (1, 2), "hi");
+   |               +    +
+
+error[E0308]: mismatched types
+  --> $DIR/add-tuple-within-arguments.rs:8:15
+   |
+LL |     bar("hi", "hi", "hi");
+   |     ---       ^^^^ expected tuple, found `&str`
+   |     |
+   |     arguments to this function are incorrect
+   |
+   = note:  expected tuple `(&str,)`
+           found reference `&'static str`
+note: function defined here
+  --> $DIR/add-tuple-within-arguments.rs:3:4
+   |
+LL | fn bar(s: &str, a: (&str,), s2: &str) {}
+   |    ^^^ -------  ----------  --------
+help: use a trailing comma to create a tuple with one element
+   |
+LL |     bar("hi", ("hi",), "hi");
+   |               +    ++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/src/test/ui/tuple/wrong_argument_ice-2.stderr b/src/test/ui/tuple/wrong_argument_ice-2.stderr
index c704ae9934b1c..0c2a4c41461fc 100644
--- a/src/test/ui/tuple/wrong_argument_ice-2.stderr
+++ b/src/test/ui/tuple/wrong_argument_ice-2.stderr
@@ -9,7 +9,7 @@ note: function defined here
    |
 LL | fn test(t: (i32, i32)) {}
    |    ^^^^ -------------
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |     test((x.qux(), x.qux()));
    |          +                +
diff --git a/src/test/ui/tuple/wrong_argument_ice.stderr b/src/test/ui/tuple/wrong_argument_ice.stderr
index 2b4cb669f5c7d..ec07f1e70cff6 100644
--- a/src/test/ui/tuple/wrong_argument_ice.stderr
+++ b/src/test/ui/tuple/wrong_argument_ice.stderr
@@ -9,7 +9,7 @@ note: associated function defined here
    |
 LL |     pub fn push_back(&mut self, value: T) {
    |            ^^^^^^^^^
-help: use parentheses to construct a tuple
+help: wrap these arguments in parentheses to construct a tuple
    |
 LL |         self.acc.push_back((self.current_provides, self.current_requires));
    |                            +                                            +

From 9f9c31171888150912487d97dba19c6586007310 Mon Sep 17 00:00:00 2001
From: DrMeepster <19316085+DrMeepster@users.noreply.github.com>
Date: Tue, 28 Jun 2022 02:19:52 -0700
Subject: [PATCH 15/21] Validate all fields of box instead of validating
 allocator specifically

---
 compiler/rustc_const_eval/src/interpret/validity.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 00e4472721f3f..702954884a08b 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -599,8 +599,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 let ptr = self.ecx.operand_field(&nonnull, 0)?;
                 self.check_safe_pointer(&ptr, "box")?;
 
-                let allocator = self.ecx.operand_field(value, 1)?;
-                self.visit_field(value, 1, &allocator)?;
+                // Check other fields of Box
+                self.walk_value(op)?;
                 Ok(true)
             }
             ty::FnPtr(_sig) => {

From 5fc1dd11a93b57d795e352e6c8718d5ffbb74dbb Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Tue, 28 Jun 2022 11:03:50 -0400
Subject: [PATCH 16/21] emit Retag for compound types with reference fields

---
 compiler/rustc_mir_transform/src/add_retag.rs | 23 +++++++++++++++----
 ...asts.SimplifyCfg-elaborate-drops.after.mir |  2 ++
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 0495439385bee..0f87e638d2618 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -33,8 +33,9 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
     })
 }
 
-/// Determine whether this type may be a reference (or box), and thus needs retagging.
-fn may_be_reference(ty: Ty<'_>) -> bool {
+/// Determine whether this type may contain a reference (or box), and thus needs retagging.
+/// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
+fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool {
     match ty.kind() {
         // Primitive types that are not references
         ty::Bool
@@ -50,8 +51,20 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
         // References
         ty::Ref(..) => true,
         ty::Adt(..) if ty.is_box() => true,
-        // Compound types are not references
-        ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false,
+        // Compound types: recurse
+        ty::Array(ty, _) | ty::Slice(ty) => {
+            // This does not branch so we keep the depth the same.
+            may_contain_reference(*ty, depth, tcx)
+        }
+        ty::Tuple(tys) => {
+            depth == 0 || tys.iter().any(|ty| may_contain_reference(ty, depth - 1, tcx))
+        }
+        ty::Adt(adt, subst) => {
+            depth == 0
+                || adt.variants().iter().any(|v| {
+                    v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, subst), depth - 1, tcx))
+                })
+        }
         // Conservative fallback
         _ => true,
     }
@@ -83,7 +96,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
             // FIXME: Instead of giving up for unstable places, we should introduce
             // a temporary and retag on that.
             is_stable(place.as_ref())
-                && may_be_reference(place.ty(&*local_decls, tcx).ty)
+                && may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
                 && is_not_temp(&local_decls[place.local])
         };
         let place_base_raw = |place: &Place<'tcx>| {
diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
index 69742d6bc3b6a..c8c45da19137f 100644
--- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
@@ -129,6 +129,7 @@ fn array_casts() -> () {
         _18 = &(*_35);                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_18);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _13 = (move _14, move _18);      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        Retag(_13);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_18);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageDead(_14);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_20);                // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -171,6 +172,7 @@ fn array_casts() -> () {
         Retag(_32);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         StorageLive(_34);                // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _34 = Option::<Arguments>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+        Retag(_34);                      // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL

From 49e6b7986a49a0ea1cd17a7853f26fe89883ef00 Mon Sep 17 00:00:00 2001
From: Gary Guo <gary@garyguo.net>
Date: Tue, 28 Jun 2022 17:18:01 +0100
Subject: [PATCH 17/21] Fix test for non-prefer-dynamic target

---
 src/test/ui/panic-runtime/need-unwind-got-abort.rs     | 1 +
 src/test/ui/panic-runtime/need-unwind-got-abort.stderr | 4 +---
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.rs b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
index 3bcc0aa39ac96..6752ecf90d2f7 100644
--- a/src/test/ui/panic-runtime/need-unwind-got-abort.rs
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
@@ -2,6 +2,7 @@
 // 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;
 
diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
index a53b7ffe57485..4c71df3ebc147 100644
--- a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
@@ -1,6 +1,4 @@
-error: the linked panic runtime `panic_unwind` is not compiled with this crate's panic strategy `abort`
-
 error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 

From 9039265c308fccf6599080db51e6db103ecaf5ad Mon Sep 17 00:00:00 2001
From: DrMeepster <19316085+DrMeepster@users.noreply.github.com>
Date: Tue, 28 Jun 2022 13:48:13 -0700
Subject: [PATCH 18/21] fix silly mistake

you should always run x.py check before pushing
---
 compiler/rustc_const_eval/src/interpret/validity.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 702954884a08b..905ab6cb578fc 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -600,7 +600,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 self.check_safe_pointer(&ptr, "box")?;
 
                 // Check other fields of Box
-                self.walk_value(op)?;
+                self.walk_value(value)?;
                 Ok(true)
             }
             ty::FnPtr(_sig) => {

From 98af1bfeccf1ec1f9e896ecc912b5cc808408378 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Wed, 22 Jun 2022 21:43:01 -0700
Subject: [PATCH 19/21] Migrate some rustc_borrowck diagnostics to
 SessionDiagnostic

---
 Cargo.lock                                    |  1 +
 compiler/rustc_borrowck/Cargo.toml            |  1 +
 .../src/diagnostics/bound_region_errors.rs    | 27 ++++++++----
 .../src/diagnostics/region_errors.rs          |  9 ++--
 compiler/rustc_borrowck/src/lib.rs            |  1 +
 .../rustc_borrowck/src/session_diagnostics.rs | 44 +++++++++++++++++++
 compiler/rustc_borrowck/src/type_check/mod.rs | 13 +-----
 .../locales/en-US/borrowck.ftl                | 18 ++++++++
 compiler/rustc_error_messages/src/lib.rs      |  1 +
 compiler/rustc_errors/src/emitter.rs          | 14 +++++-
 src/test/ui/dst/dst-index.stderr              |  8 ++--
 src/test/ui/error-codes/E0161.base.stderr     |  4 +-
 .../issue-59311.stderr                        |  4 +-
 .../ui/lifetimes/re-empty-in-error.stderr     |  2 +-
 src/test/ui/mir/issue-67947.rs                |  2 +-
 src/test/ui/mir/issue-67947.stderr            |  4 +-
 .../object-safety-by-value-self-use.rs        |  2 +-
 .../object-safety-by-value-self-use.stderr    |  4 +-
 .../return-unsized-from-trait-method.rs       |  2 +-
 .../return-unsized-from-trait-method.stderr   |  4 +-
 20 files changed, 122 insertions(+), 43 deletions(-)
 create mode 100644 compiler/rustc_borrowck/src/session_diagnostics.rs
 create mode 100644 compiler/rustc_error_messages/locales/en-US/borrowck.ftl

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_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/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/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
 

From 23f3b0dfd04812b03da0df4d5dfad0fef39c6862 Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 28 Jun 2022 19:32:12 -0700
Subject: [PATCH 20/21] Don't point at another arg if we're already pointing at
 one

---
 .../rustc_typeck/src/check/fn_ctxt/checks.rs  | 38 +++++++++++++++----
 src/test/ui/proc-macro/signature.stderr       |  5 +--
 src/test/ui/unsized/unsized-fn-param.stderr   | 16 ++++++--
 src/test/ui/unsized/unsized3.rs               |  1 +
 src/test/ui/unsized/unsized3.stderr           | 35 ++++++++++++++++-
 5 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index ede2ed5169f80..dc49ff90f34b0 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1629,7 +1629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        for error in errors {
+        'outer: for error in errors {
             // Only if the cause is somewhere inside the expression we want try to point at arg.
             // Otherwise, it means that the cause is somewhere else and we should not change
             // anything because we can break the correct span.
@@ -1671,10 +1671,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => continue,
                 };
             let self_ = self.resolve_vars_if_possible(self_);
+            let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_);
+
+            let typeck_results = self.typeck_results.borrow();
+
+            for (idx, arg) in args.iter().enumerate() {
+                // Don't adjust the span if we already have a more precise span
+                // within one of the args.
+                if arg.span.contains(error.obligation.cause.span) {
+                    let references_arg =
+                        typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self)
+                            || expected_tys.get(idx).copied().map_or(false, &ty_matches_self);
+                    if references_arg && !arg.span.from_expansion() {
+                        error.obligation.cause.map_code(|parent_code| {
+                            ObligationCauseCode::FunctionArgumentObligation {
+                                arg_hir_id: args[idx].hir_id,
+                                call_hir_id: expr.hir_id,
+                                parent_code,
+                            }
+                        })
+                    }
+                    continue 'outer;
+                }
+            }
 
             // Collect the argument position for all arguments that could have caused this
             // `FulfillmentError`.
-            let typeck_results = self.typeck_results.borrow();
             let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args)
                 .enumerate()
                 .flat_map(|(idx, (expected_ty, arg))| {
@@ -1688,7 +1710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let ty = self.resolve_vars_if_possible(ty);
                     // We walk the argument type because the argument's type could have
                     // been `Option<T>`, but the `FulfillmentError` references `T`.
-                    if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
+                    if ty_matches_self(ty) { Some(i) } else { None }
                 })
                 .collect();
 
@@ -1699,18 +1721,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             referenced_in.sort_unstable();
             referenced_in.dedup();
 
-            if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+            if let &[idx] = &referenced_in[..] {
                 // Do not point at the inside of a macro.
                 // That would often result in poor error messages.
-                if args[ref_in].span.from_expansion() {
-                    return;
+                if args[idx].span.from_expansion() {
+                    continue;
                 }
                 // We make sure that only *one* argument matches the obligation failure
                 // and we assign the obligation's span to its expression's.
-                error.obligation.cause.span = args[ref_in].span;
+                error.obligation.cause.span = args[idx].span;
                 error.obligation.cause.map_code(|parent_code| {
                     ObligationCauseCode::FunctionArgumentObligation {
-                        arg_hir_id: args[ref_in].hir_id,
+                        arg_hir_id: args[idx].hir_id,
                         call_hir_id: expr.hir_id,
                         parent_code,
                     }
diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr
index 78b0beff0da39..a6bd98ddb1977 100644
--- a/src/test/ui/proc-macro/signature.stderr
+++ b/src/test/ui/proc-macro/signature.stderr
@@ -5,10 +5,7 @@ LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
 LL | |
 LL | |     loop {}
 LL | | }
-   | | ^
-   | | |
-   | |_call the function in a closure: `|| unsafe { /* code */ }`
-   |   required by a bound introduced by this call
+   | |_^ call the function in a closure: `|| unsafe { /* code */ }`
    |
    = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
    = note: unsafe function cannot be called generically without an unsafe block
diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr
index 3eecca0fa09d9..edf0b89596536 100644
--- a/src/test/ui/unsized/unsized-fn-param.stderr
+++ b/src/test/ui/unsized/unsized-fn-param.stderr
@@ -2,7 +2,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:11:11
    |
 LL |     foo11("bar", &"baz");
-   |           ^^^^^ doesn't have a size known at compile-time
+   |     ----- ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<Path>`
@@ -15,7 +17,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:13:19
    |
 LL |     foo12(&"bar", "baz");
-   |                   ^^^^^ doesn't have a size known at compile-time
+   |     -----         ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<Path>`
@@ -28,7 +32,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:16:11
    |
 LL |     foo21("bar", &"baz");
-   |           ^^^^^ doesn't have a size known at compile-time
+   |     ----- ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<str>`
@@ -41,7 +47,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
   --> $DIR/unsized-fn-param.rs:18:19
    |
 LL |     foo22(&"bar", "baz");
-   |                   ^^^^^ doesn't have a size known at compile-time
+   |     -----         ^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `str`
    = note: required for the cast to the object type `dyn AsRef<str>`
diff --git a/src/test/ui/unsized/unsized3.rs b/src/test/ui/unsized/unsized3.rs
index 39b6583bc4ec4..af76aca2c2958 100644
--- a/src/test/ui/unsized/unsized3.rs
+++ b/src/test/ui/unsized/unsized3.rs
@@ -44,6 +44,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
 fn f10<X: ?Sized>(x1: Box<S<X>>) {
     f5(&(32, *x1));
     //~^ ERROR the size for values of type
+    //~| ERROR the size for values of type
 }
 
 pub fn main() {}
diff --git a/src/test/ui/unsized/unsized3.stderr b/src/test/ui/unsized/unsized3.stderr
index 65bdc4c2ea352..d64091b15eb1f 100644
--- a/src/test/ui/unsized/unsized3.stderr
+++ b/src/test/ui/unsized/unsized3.stderr
@@ -100,6 +100,29 @@ LL - fn f9<X: ?Sized>(x1: Box<S<X>>) {
 LL + fn f9<X>(x1: Box<S<X>>) {
    |
 
+error[E0277]: the size for values of type `X` cannot be known at compilation time
+  --> $DIR/unsized3.rs:45:9
+   |
+LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
+   |        - this type parameter needs to be `std::marker::Sized`
+LL |     f5(&(32, *x1));
+   |     --  ^^^^^^^^^ doesn't have a size known at compile-time
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required because it appears within the type `S<X>`
+  --> $DIR/unsized3.rs:28:8
+   |
+LL | struct S<X: ?Sized> {
+   |        ^
+   = note: required because it appears within the type `({integer}, S<X>)`
+   = note: tuples must have a statically known size to be initialized
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
+LL + fn f10<X>(x1: Box<S<X>>) {
+   |
+
 error[E0277]: the size for values of type `X` cannot be known at compilation time
   --> $DIR/unsized3.rs:45:8
    |
@@ -116,13 +139,21 @@ note: required because it appears within the type `S<X>`
 LL | struct S<X: ?Sized> {
    |        ^
    = note: required because it appears within the type `({integer}, S<X>)`
-   = note: tuples must have a statically known size to be initialized
+note: required by a bound in `f5`
+  --> $DIR/unsized3.rs:24:7
+   |
+LL | fn f5<Y>(x: &Y) {}
+   |       ^ required by this bound in `f5`
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
 LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
 LL + fn f10<X>(x1: Box<S<X>>) {
    |
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn f5<Y: ?Sized>(x: &Y) {}
+   |        ++++++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.

From 1e40200b353926308a9a8a5f3349df8dc6bf8f80 Mon Sep 17 00:00:00 2001
From: kadmin <julianknodt@gmail.com>
Date: Sat, 25 Jun 2022 09:59:48 +0000
Subject: [PATCH 21/21] Erase regions in new abstract consts

---
 .../src/traits/const_evaluatable.rs           |  3 +-
 .../try_unify_ignore_lifetimes.rs             | 33 +++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/const-generics/try_unify_ignore_lifetimes.rs

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/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() {}