about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auxiliary/rust_test_helpers.c24
-rw-r--r--tests/codegen/cast-target-abi.rs280
-rw-r--r--tests/codegen/cffi/ffi-out-of-bounds-loads.rs28
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff)2
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff (renamed from tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff)2
-rw-r--r--tests/mir-opt/const_prop/pointer_expose_provenance.rs (renamed from tests/mir-opt/const_prop/pointer_expose_address.rs)4
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff2
-rw-r--r--tests/mir-opt/const_prop/reify_fn_ptr.rs2
-rw-r--r--tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff4
-rw-r--r--tests/mir-opt/dead-store-elimination/provenance_soundness.rs4
-rw-r--r--tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff (renamed from tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff)8
-rw-r--r--tests/mir-opt/simplify_locals.rs6
-rw-r--r--tests/ui/abi/extern/extern-pass-FiveU16s.rs30
-rw-r--r--tests/ui/abi/extern/extern-return-FiveU16s.rs26
-rw-r--r--tests/ui/async-await/coroutine-desc.stderr28
-rw-r--r--tests/ui/closures/issue-1460.rs (renamed from tests/ui/issues/issue-1460.rs)0
-rw-r--r--tests/ui/closures/issue-1460.stderr (renamed from tests/ui/issues/issue-1460.stderr)0
-rw-r--r--tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr10
-rw-r--r--tests/ui/fn/fn-item-type.stderr50
-rw-r--r--tests/ui/fn/issue-1451.rs (renamed from tests/ui/issues/issue-1451.rs)0
-rw-r--r--tests/ui/fn/issue-1900.rs (renamed from tests/ui/issues/issue-1900.rs)0
-rw-r--r--tests/ui/fn/issue-1900.stderr (renamed from tests/ui/issues/issue-1900.stderr)0
-rw-r--r--tests/ui/issues/issue-1476.rs3
-rw-r--r--tests/ui/issues/issue-1476.stderr9
-rw-r--r--tests/ui/issues/issue-1696.rs8
-rw-r--r--tests/ui/lint/lint-strict-provenance-lossy-casts.stderr8
-rw-r--r--tests/ui/loops/issue-1962.fixed (renamed from tests/ui/issues/issue-1962.fixed)0
-rw-r--r--tests/ui/loops/issue-1962.rs (renamed from tests/ui/issues/issue-1962.rs)0
-rw-r--r--tests/ui/loops/issue-1962.stderr (renamed from tests/ui/issues/issue-1962.stderr)0
-rw-r--r--tests/ui/loops/issue-1974.rs (renamed from tests/ui/issues/issue-1974.rs)0
-rw-r--r--tests/ui/match/postfix-match/match-after-as.rs7
-rw-r--r--tests/ui/match/postfix-match/match-after-as.stderr28
-rw-r--r--tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs14
-rw-r--r--tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr97
-rw-r--r--tests/ui/mismatched_types/issue-1362.rs (renamed from tests/ui/issues/issue-1362.rs)0
-rw-r--r--tests/ui/mismatched_types/issue-1362.stderr (renamed from tests/ui/issues/issue-1362.stderr)0
-rw-r--r--tests/ui/mismatched_types/issue-1448-2.rs (renamed from tests/ui/issues/issue-1448-2.rs)0
-rw-r--r--tests/ui/mismatched_types/issue-1448-2.stderr (renamed from tests/ui/issues/issue-1448-2.stderr)0
-rw-r--r--tests/ui/pattern/usefulness/unions.rs35
-rw-r--r--tests/ui/pattern/usefulness/unions.stderr34
-rw-r--r--tests/ui/simd/intrinsic/ptr-cast.rs4
-rw-r--r--tests/ui/static/issue-1660.rs (renamed from tests/ui/issues/issue-1660.rs)0
42 files changed, 682 insertions, 75 deletions
diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c
index 977ea487a98..965df44c676 100644
--- a/tests/auxiliary/rust_test_helpers.c
+++ b/tests/auxiliary/rust_test_helpers.c
@@ -118,6 +118,30 @@ rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
     return u;
 }
 
+struct FiveU16s {
+    uint16_t one;
+    uint16_t two;
+    uint16_t three;
+    uint16_t four;
+    uint16_t five;
+};
+
+struct FiveU16s
+rust_dbg_extern_return_FiveU16s() {
+    struct FiveU16s s;
+    s.one = 10;
+    s.two = 20;
+    s.three = 30;
+    s.four = 40;
+    s.five = 50;
+    return s;
+}
+
+struct FiveU16s
+rust_dbg_extern_identity_FiveU16s(struct FiveU16s u) {
+    return u;
+}
+
 struct ManyInts {
     int8_t arg1;
     int16_t arg2;
diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs
new file mode 100644
index 00000000000..e6024f03425
--- /dev/null
+++ b/tests/codegen/cast-target-abi.rs
@@ -0,0 +1,280 @@
+// ignore-tidy-linelength
+//@ revisions:aarch64 loongarch64 powerpc64 sparc64
+//@ compile-flags: -O -C no-prepopulate-passes
+
+//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
+//@[aarch64] needs-llvm-components: arm
+//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
+//@[loongarch64] needs-llvm-components: loongarch
+//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
+//@[powerpc64] needs-llvm-components: powerpc
+//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
+//@[sparc64] needs-llvm-components: sparc
+
+// Tests that arguments with `PassMode::Cast` are handled correctly.
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
+
+// This struct will be passed as a single `i64` or `i32`.
+// This may be (if `i64)) larger than the Rust layout, which is just `{ i16, i16 }`.
+#[repr(C)]
+pub struct TwoU16s {
+    a: u16,
+    b: u16,
+}
+
+// This struct will be passed as `[2 x i64]`.
+// This is larger than the Rust layout.
+#[repr(C)]
+pub struct FiveU16s {
+    a: u16,
+    b: u16,
+    c: u16,
+    d: u16,
+    e: u16,
+}
+
+// This struct will be passed as `[2 x double]`.
+// This is the same as the Rust layout.
+#[repr(C)]
+pub struct DoubleDouble {
+    f: f64,
+    g: f64,
+}
+
+// On loongarch, this struct will be passed as `{ double, float }`.
+// This is smaller than the Rust layout, which has trailing padding (`{ f64, f32, <f32 padding> }`)
+#[repr(C)]
+pub struct DoubleFloat {
+    f: f64,
+    g: f32,
+}
+
+extern "C" {
+    fn receives_twou16s(x: TwoU16s);
+    fn returns_twou16s() -> TwoU16s;
+
+    fn receives_fiveu16s(x: FiveU16s);
+    fn returns_fiveu16s() -> FiveU16s;
+
+    fn receives_doubledouble(x: DoubleDouble);
+    fn returns_doubledouble() -> DoubleDouble;
+
+    // These functions cause an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+    #[cfg(not(target_arch = "sparc64"))]
+    fn receives_doublefloat(x: DoubleFloat);
+    #[cfg(not(target_arch = "sparc64"))]
+    fn returns_doublefloat() -> DoubleFloat;
+}
+
+// CHECK-LABEL: @call_twou16s
+#[no_mangle]
+pub unsafe fn call_twou16s() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i32]], align [[ABI_ALIGN:4]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 4, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_twou16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = TwoU16s { a: 1, b: 2 };
+    receives_twou16s(x);
+}
+
+// CHECK-LABEL: @return_twou16s
+#[no_mangle]
+pub unsafe fn return_twou16s() -> TwoU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %TwoU16s, align 2
+    // powerpc64: call void @returns_twou16s(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:i64]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %TwoU16s, align [[RUST_ALIGN:2]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_twou16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 4, i1 false)
+    returns_twou16s()
+}
+
+// CHECK-LABEL: @call_fiveu16s
+#[no_mangle]
+pub unsafe fn call_fiveu16s() {
+    // CHECK: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %FiveU16s, align 2
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 10, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_fiveu16s([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = FiveU16s { a: 1, b: 2, c: 3, d: 4, e: 5 };
+    receives_fiveu16s(x);
+}
+
+// CHECK-LABEL: @return_fiveu16s
+// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]])
+#[no_mangle]
+pub unsafe fn return_fiveu16s() -> FiveU16s {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: call void @returns_fiveu16s(ptr {{.+}} [[RET_PTR]])
+
+
+    // The other targets copy the cast ABI type to the sret pointer.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_fiveu16s()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RET_PTR]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 10, i1 false)
+    returns_fiveu16s()
+}
+
+// CHECK-LABEL: @call_doubledouble
+#[no_mangle]
+pub unsafe fn call_doubledouble() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // CHECK: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // CHECK: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // CHECK: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // CHECK: call void @receives_doubledouble([[ABI_TYPE]] [[ABI_VALUE]])
+    let x = DoubleDouble { f: 1., g: 2. };
+    receives_doubledouble(x);
+}
+
+// CHECK-LABEL: @return_doubledouble
+#[no_mangle]
+pub unsafe fn return_doubledouble() -> DoubleDouble {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleDouble, align 8
+    // powerpc64: call void @returns_doubledouble(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x double\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+    // sparc64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, double }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+    // sparc64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleDouble, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+    // sparc64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doubledouble()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // sparc64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // sparc64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    returns_doubledouble()
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @call_doublefloat
+// loongarch64-LABEL: @call_doublefloat
+// powerpc64-LABEL:   @call_doublefloat
+#[no_mangle]
+pub unsafe fn call_doublefloat() {
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+    // powerpc64:   [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // powerpc64:   [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 12, i1 false)
+    // powerpc64:   call void @llvm.memcpy.{{.+}}(ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], i64 16, i1 false)
+
+    // aarch64:     [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // powerpc64:   [[ABI_VALUE:%.+]] = load [[ABI_TYPE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // loongarch64: call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    // powerpc64:   call void @receives_doublefloat([[ABI_TYPE]] {{(inreg )?}}[[ABI_VALUE]])
+    let x = DoubleFloat { f: 1., g: 2. };
+    receives_doublefloat(x);
+}
+
+// This test causes an ICE in sparc64 ABI code (https://github.com/rust-lang/rust/issues/122620)
+#[cfg(not(target_arch = "sparc64"))]
+// aarch64-LABEL:     @return_doublefloat
+// loongarch64-LABEL: @return_doublefloat
+// powerpc64-LABEL:   @return_doublefloat
+#[no_mangle]
+pub unsafe fn return_doublefloat() -> DoubleFloat {
+    // powerpc returns this struct via sret pointer, it doesn't use the cast ABI.
+
+    // powerpc64: [[RETVAL:%.+]] = alloca %DoubleFloat, align 8
+    // powerpc64: call void @returns_doublefloat(ptr {{.+}} [[RETVAL]])
+
+
+    // The other targets copy the cast ABI type to an alloca.
+
+    // aarch64:     [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:\[2 x i64\]]], align [[ABI_ALIGN:8]]
+    // loongarch64: [[ABI_ALLOCA:%.+]] = alloca [[ABI_TYPE:{ double, float }]], align [[ABI_ALIGN:8]]
+
+    // aarch64:     [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+    // loongarch64: [[RUST_ALLOCA:%.+]] = alloca %DoubleFloat, align [[RUST_ALIGN:8]]
+
+    // aarch64:     [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+    // loongarch64: [[ABI_VALUE:%.+]] = call [[ABI_TYPE]] @returns_doublefloat()
+
+    // aarch64:     store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+    // loongarch64: store [[ABI_TYPE]] [[ABI_VALUE]], ptr [[ABI_ALLOCA]], align [[ABI_ALIGN]]
+
+    // aarch64:     call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 16, i1 false)
+    // loongarch64: call void @llvm.memcpy.{{.+}}(ptr align [[RUST_ALIGN]] [[RUST_ALLOCA]], ptr align [[ABI_ALIGN]] [[ABI_ALLOCA]], i64 12, i1 false)
+    returns_doublefloat()
+}
diff --git a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
index 7eda6cf4d57..8b32e902b3f 100644
--- a/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
+++ b/tests/codegen/cffi/ffi-out-of-bounds-loads.rs
@@ -1,8 +1,21 @@
+//@ revisions: linux apple
+//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+
 // Regression test for #29988
 
-//@ compile-flags: -C no-prepopulate-passes
-//@ only-x86_64
-//@ ignore-windows
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang="sized"] trait Sized { }
+#[lang="freeze"] trait Freeze { }
+#[lang="copy"] trait Copy { }
 
 #[repr(C)]
 struct S {
@@ -15,11 +28,14 @@ extern "C" {
     fn foo(s: S);
 }
 
-fn main() {
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
     let s = S { f1: 1, f2: 2, f3: 3 };
     unsafe {
-        // CHECK: load { i64, i32 }, {{.*}}, align 4
-        // CHECK: call void @foo({ i64, i32 } {{.*}})
+        // CHECK: [[ALLOCA:%.+]] = alloca { i64, i32 }, align 8
+        // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
+        // CHECK: call void @foo({ i64, i32 } [[LOAD]])
         foo(s);
     }
 }
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
index 596eb1a9966..79a95b618d1 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
index 995f281ecf5..9d1bcd92fef 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.main.GVN.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const main::FOO;
           _2 = &raw const (*_3);
-          _1 = move _2 as usize (PointerExposeAddress);
+          _1 = move _2 as usize (PointerExposeProvenance);
           StorageDead(_2);
           StorageDead(_3);
           StorageLive(_4);
diff --git a/tests/mir-opt/const_prop/pointer_expose_address.rs b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
index a6b4f8857c3..840a4d65f3d 100644
--- a/tests/mir-opt/const_prop/pointer_expose_address.rs
+++ b/tests/mir-opt/const_prop/pointer_expose_provenance.rs
@@ -4,12 +4,12 @@
 #[inline(never)]
 fn read(_: usize) { }
 
-// EMIT_MIR pointer_expose_address.main.GVN.diff
+// EMIT_MIR pointer_expose_provenance.main.GVN.diff
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = const main::FOO;
     // CHECK: [[ref:_.*]] = &raw const (*[[ptr]]);
-    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeAddress);
+    // CHECK: [[x:_.*]] = move [[ref]] as usize (PointerExposeProvenance);
     // CHECK: = read([[x]])
     const FOO: &i32 = &1;
     let x = FOO as *const i32 as usize;
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
index 2f76e74a3f8..e5786bcf701 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.main.GVN.diff
@@ -14,7 +14,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = main as fn() (PointerCoercion(ReifyFnPointer));
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           _1 = move _2 as *const fn() (PointerWithExposedProvenance);
           StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/reify_fn_ptr.rs b/tests/mir-opt/const_prop/reify_fn_ptr.rs
index 4e897d22768..55dca24f3d2 100644
--- a/tests/mir-opt/const_prop/reify_fn_ptr.rs
+++ b/tests/mir-opt/const_prop/reify_fn_ptr.rs
@@ -4,7 +4,7 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: [[ptr:_.*]] = main as fn() (PointerCoercion(ReifyFnPointer));
-    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeAddress);
+    // CHECK: [[addr:_.*]] = move [[ptr]] as usize (PointerExposeProvenance);
     // CHECK: [[back:_.*]] = move [[addr]] as *const fn() (PointerWithExposedProvenance);
     let _ = main as usize as *const fn();
 }
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
index 9b0dc6b6af6..56d5c24ae1d 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
@@ -19,12 +19,12 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = move _5 as isize (PointerExposeAddress);
+          _4 = move _5 as isize (PointerExposeProvenance);
           StorageDead(_5);
           _0 = const ();
           StorageDead(_4);
diff --git a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
index 96268cd957e..20517a00489 100644
--- a/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
+++ b/tests/mir-opt/dead-store-elimination/provenance_soundness.rs
@@ -5,8 +5,8 @@
 // EMIT_MIR provenance_soundness.pointer_to_int.DeadStoreElimination-initial.diff
 fn pointer_to_int(p: *mut i32) {
     // CHECK-LABEL: fn pointer_to_int(
-    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeAddress);
-    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeAddress);
+    // CHECK: {{_.*}} = {{.*}} as usize (PointerExposeProvenance);
+    // CHECK: {{_.*}} = {{.*}} as isize (PointerExposeProvenance);
     let _x = p as usize;
     let _y = p as isize;
 }
diff --git a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
index 9ebee3df62c..cc5c642407e 100644
--- a/tests/mir-opt/simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
+++ b/tests/mir-opt/simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
@@ -1,7 +1,7 @@
-- // MIR for `expose_addr` before SimplifyLocals-before-const-prop
-+ // MIR for `expose_addr` after SimplifyLocals-before-const-prop
+- // MIR for `expose_provenance` before SimplifyLocals-before-const-prop
++ // MIR for `expose_provenance` after SimplifyLocals-before-const-prop
   
-  fn expose_addr(_1: *const usize) -> () {
+  fn expose_provenance(_1: *const usize) -> () {
       debug p => _1;
       let mut _0: ();
       let _2: usize;
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = move _3 as usize (PointerExposeAddress);
+          _2 = move _3 as usize (PointerExposeProvenance);
           StorageDead(_3);
           StorageDead(_2);
           _0 = const ();
diff --git a/tests/mir-opt/simplify_locals.rs b/tests/mir-opt/simplify_locals.rs
index f95e9185f44..756679e77e3 100644
--- a/tests/mir-opt/simplify_locals.rs
+++ b/tests/mir-opt/simplify_locals.rs
@@ -63,8 +63,8 @@ fn t4() -> u32 {
     unsafe { X + 1 }
 }
 
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals-before-const-prop.diff
-fn expose_addr(p: *const usize) {
+// EMIT_MIR simplify_locals.expose_provenance.SimplifyLocals-before-const-prop.diff
+fn expose_provenance(p: *const usize) {
     // Used pointer to address cast. Has a side effect of exposing the provenance.
     p as usize;
 }
@@ -78,5 +78,5 @@ fn main() {
     t2();
     t3();
     t4();
-    expose_addr(&0);
+    expose_provenance(&0);
 }
diff --git a/tests/ui/abi/extern/extern-pass-FiveU16s.rs b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
new file mode 100644
index 00000000000..5f1307beb28
--- /dev/null
+++ b/tests/ui/abi/extern/extern-pass-FiveU16s.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+// Test a foreign function that accepts and returns a struct by value.
+
+// FiveU16s in particular is interesting because it is larger than a single 64 bit or 32 bit
+// register, which are used as cast destinations on some targets, but does not evenly divide those
+// sizes, causing there to be padding in the last element.
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_identity_FiveU16s(v: FiveU16s) -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let x = FiveU16s { one: 22, two: 23, three: 24, four: 25, five: 26 };
+        let y = rust_dbg_extern_identity_FiveU16s(x);
+        assert_eq!(x, y);
+    }
+}
diff --git a/tests/ui/abi/extern/extern-return-FiveU16s.rs b/tests/ui/abi/extern/extern-return-FiveU16s.rs
new file mode 100644
index 00000000000..d8ae8b2661c
--- /dev/null
+++ b/tests/ui/abi/extern/extern-return-FiveU16s.rs
@@ -0,0 +1,26 @@
+//@ run-pass
+#![allow(improper_ctypes)]
+
+pub struct FiveU16s {
+    one: u16,
+    two: u16,
+    three: u16,
+    four: u16,
+    five: u16,
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_extern_return_FiveU16s() -> FiveU16s;
+}
+
+pub fn main() {
+    unsafe {
+        let y = rust_dbg_extern_return_FiveU16s();
+        assert_eq!(y.one, 10);
+        assert_eq!(y.two, 20);
+        assert_eq!(y.three, 30);
+        assert_eq!(y.four, 40);
+        assert_eq!(y.five, 50);
+    }
+}
diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr
index e4cb0915a10..1f1e303ea4c 100644
--- a/tests/ui/async-await/coroutine-desc.stderr
+++ b/tests/ui/async-await/coroutine-desc.stderr
@@ -5,6 +5,7 @@ LL |     fun(async {}, async {});
    |     --- --------  ^^^^^^^^ expected `async` block, found a different `async` block
    |     |   |
    |     |   the expected `async` block
+   |     |   expected all arguments to be this `async` block type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}`
@@ -13,14 +14,18 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` block type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` block type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:12:16
    |
 LL |     fun(one(), two());
-   |     ---        ^^^^^ expected future, found a different future
-   |     |
+   |     --- -----  ^^^^^ expected future, found a different future
+   |     |   |
+   |     |   expected all arguments to be this future type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = help: consider `await`ing on both `Future`s
@@ -29,15 +34,19 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the future type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the future type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error[E0308]: mismatched types
   --> $DIR/coroutine-desc.rs:14:26
    |
 LL |     fun((async || {})(), (async || {})());
-   |     ---           --     ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
-   |     |             |
-   |     |             the expected `async` closure body
+   |     --- ---------------  ^^^^^^^^^^^^^^^ expected `async` closure body, found a different `async` closure body
+   |     |   |         |
+   |     |   |         the expected `async` closure body
+   |     |   expected all arguments to be this `async` closure body type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}`
@@ -46,7 +55,10 @@ note: function defined here
   --> $DIR/coroutine-desc.rs:8:4
    |
 LL | fn fun<F: Future<Output = ()>>(f1: F, f2: F) {}
-   |    ^^^                                -----
+   |    ^^^ -                       -----  ----- this parameter needs to match the `async` closure body type of `f1`
+   |        |                       |
+   |        |                       `f2` needs to match the `async` closure body type of this parameter
+   |        `f1` and `f2` all reference this parameter F
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-1460.rs b/tests/ui/closures/issue-1460.rs
index c201f026bca..c201f026bca 100644
--- a/tests/ui/issues/issue-1460.rs
+++ b/tests/ui/closures/issue-1460.rs
diff --git a/tests/ui/issues/issue-1460.stderr b/tests/ui/closures/issue-1460.stderr
index d4a8c8955e2..d4a8c8955e2 100644
--- a/tests/ui/issues/issue-1460.stderr
+++ b/tests/ui/closures/issue-1460.stderr
diff --git a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
index 498ef33d52e..46723c5a297 100644
--- a/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
+++ b/tests/ui/coercion/coerce-reborrow-multi-arg-fail.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
    |
 LL |     test(&mut 7, &7);
-   |     ----         ^^ types differ in mutability
-   |     |
+   |     ---- ------  ^^ types differ in mutability
+   |     |    |
+   |     |    expected all arguments to be this `&mut {integer}` type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected mutable reference `&mut {integer}`
@@ -12,7 +13,10 @@ note: function defined here
   --> $DIR/coerce-reborrow-multi-arg-fail.rs:1:4
    |
 LL | fn test<T>(_a: T, _b: T) {}
-   |    ^^^^           -----
+   |    ^^^^ -  -----  ----- this parameter needs to match the `&mut {integer}` type of `_a`
+   |         |  |
+   |         |  `_b` needs to match the `&mut {integer}` type of this parameter
+   |         `_a` and `_b` all reference this parameter T
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/fn/fn-item-type.stderr b/tests/ui/fn/fn-item-type.stderr
index da90b8b81c8..76cdbcceac8 100644
--- a/tests/ui/fn/fn-item-type.stderr
+++ b/tests/ui/fn/fn-item-type.stderr
@@ -2,8 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:22:19
    |
 LL |     eq(foo::<u8>, bar::<u8>);
-   |     --            ^^^^^^^^^ expected fn item, found a different fn item
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected fn item, found a different fn item
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -13,15 +14,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
    |
 LL |     eq(foo::<u8>, foo::<i8>);
-   |     --            ^^^^^^^^^ expected `u8`, found `i8`
-   |     |
+   |     -- ---------  ^^^^^^^^^ expected `u8`, found `i8`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -31,15 +36,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
    |
 LL |     eq(bar::<String>, bar::<Vec<u8>>);
-   |     --                ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
-   |     |
+   |     -- -------------  ^^^^^^^^^^^^^^ expected `String`, found `Vec<u8>`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {bar::<String>}`
@@ -49,15 +58,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:40:26
    |
 LL |     eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
-   |     --                   ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
-   |     |
+   |     -- ----------------  ^^^^^^^^^^^^^^^^^ expected `u8`, found `u16`
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn() {<u8 as Foo>::foo}`
@@ -67,15 +80,19 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
    = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:45:19
    |
 LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
-   |     --            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
-   |     |
+   |     -- ---------  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found fn pointer
+   |     |  |
+   |     |  expected all arguments to be this fn item type because they need to match the type of this parameter
    |     arguments to this function are incorrect
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
@@ -85,7 +102,10 @@ note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
 LL | fn eq<T>(x: T, y: T) {}
-   |    ^^          ----
+   |    ^^ -  ----  ---- this parameter needs to match the fn item type of `x`
+   |       |  |
+   |       |  `y` needs to match the fn item type of this parameter
+   |       `x` and `y` all reference this parameter T
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/issues/issue-1451.rs b/tests/ui/fn/issue-1451.rs
index 735b766bd0c..735b766bd0c 100644
--- a/tests/ui/issues/issue-1451.rs
+++ b/tests/ui/fn/issue-1451.rs
diff --git a/tests/ui/issues/issue-1900.rs b/tests/ui/fn/issue-1900.rs
index 761bd317027..761bd317027 100644
--- a/tests/ui/issues/issue-1900.rs
+++ b/tests/ui/fn/issue-1900.rs
diff --git a/tests/ui/issues/issue-1900.stderr b/tests/ui/fn/issue-1900.stderr
index 31fd46c8e2a..31fd46c8e2a 100644
--- a/tests/ui/issues/issue-1900.stderr
+++ b/tests/ui/fn/issue-1900.stderr
diff --git a/tests/ui/issues/issue-1476.rs b/tests/ui/issues/issue-1476.rs
deleted file mode 100644
index 138570a93c4..00000000000
--- a/tests/ui/issues/issue-1476.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("{}", x); //~ ERROR cannot find value `x` in this scope
-}
diff --git a/tests/ui/issues/issue-1476.stderr b/tests/ui/issues/issue-1476.stderr
deleted file mode 100644
index e30dbfd205b..00000000000
--- a/tests/ui/issues/issue-1476.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `x` in this scope
-  --> $DIR/issue-1476.rs:2:20
-   |
-LL |     println!("{}", x);
-   |                    ^ not found in this scope
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/issues/issue-1696.rs b/tests/ui/issues/issue-1696.rs
deleted file mode 100644
index 08002ad3c58..00000000000
--- a/tests/ui/issues/issue-1696.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ run-pass
-use std::collections::HashMap;
-
-pub fn main() {
-    let mut m = HashMap::new();
-    m.insert(b"foo".to_vec(), b"bar".to_vec());
-    println!("{:?}", m);
-}
diff --git a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
index aa151fe2d21..390028b349e 100644
--- a/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/tests/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -4,7 +4,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr: usize = &x as *const u8 as usize;
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 note: the lint level is defined here
   --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
    |
@@ -21,7 +21,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr_32bit = &x as *const u8 as u32;
    |                      ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 help: use `.addr()` to obtain the address of a pointer
    |
 LL |     let addr_32bit = (&x as *const u8).addr() as u32;
@@ -35,7 +35,7 @@ LL |     let ptr_addr = ptr as usize;
    |                       |
    |                       help: use `.addr()` to obtain the address of a pointer: `.addr()`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:16:26
@@ -45,7 +45,7 @@ LL |     let ptr_addr_32bit = ptr as u32;
    |                             |
    |                             help: use `.addr()` to obtain the address of a pointer: `.addr() as u32`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/issues/issue-1962.fixed b/tests/ui/loops/issue-1962.fixed
index f0002be4bea..f0002be4bea 100644
--- a/tests/ui/issues/issue-1962.fixed
+++ b/tests/ui/loops/issue-1962.fixed
diff --git a/tests/ui/issues/issue-1962.rs b/tests/ui/loops/issue-1962.rs
index 9c8fb500ba3..9c8fb500ba3 100644
--- a/tests/ui/issues/issue-1962.rs
+++ b/tests/ui/loops/issue-1962.rs
diff --git a/tests/ui/issues/issue-1962.stderr b/tests/ui/loops/issue-1962.stderr
index db235d47303..db235d47303 100644
--- a/tests/ui/issues/issue-1962.stderr
+++ b/tests/ui/loops/issue-1962.stderr
diff --git a/tests/ui/issues/issue-1974.rs b/tests/ui/loops/issue-1974.rs
index ea67b2541de..ea67b2541de 100644
--- a/tests/ui/issues/issue-1974.rs
+++ b/tests/ui/loops/issue-1974.rs
diff --git a/tests/ui/match/postfix-match/match-after-as.rs b/tests/ui/match/postfix-match/match-after-as.rs
new file mode 100644
index 00000000000..7c648bfcf03
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.rs
@@ -0,0 +1,7 @@
+#![feature(postfix_match)]
+
+fn main() {
+    1 as i32.match {};
+    //~^ ERROR cast cannot be followed by a postfix match
+    //~| ERROR non-exhaustive patterns
+}
diff --git a/tests/ui/match/postfix-match/match-after-as.stderr b/tests/ui/match/postfix-match/match-after-as.stderr
new file mode 100644
index 00000000000..68e4762b8d9
--- /dev/null
+++ b/tests/ui/match/postfix-match/match-after-as.stderr
@@ -0,0 +1,28 @@
+error: cast cannot be followed by a postfix match
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+help: try surrounding the expression in parentheses
+   |
+LL |     (1 as i32).match {};
+   |     +        +
+
+error[E0004]: non-exhaustive patterns: type `i32` is non-empty
+  --> $DIR/match-after-as.rs:4:5
+   |
+LL |     1 as i32.match {};
+   |     ^^^^^^^^
+   |
+   = note: the matched value is of type `i32`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+   |
+LL ~     1 as i32.match {
+LL +         _ => todo!(),
+LL ~     };
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
new file mode 100644
index 00000000000..2bd10e762d9
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.rs
@@ -0,0 +1,14 @@
+fn foo<T>(a: T, b: T) {}
+fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+
+fn main() {
+    foo(1, 2.);
+    //~^  ERROR mismatched types
+    foo_multi_same("a", "b", false, true, (), 32);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+    //~^  ERROR arguments to this function are incorrect
+    foo_multi_same("a", 1, 2, "d", "e", 32);
+    //~^  ERROR arguments to this function are incorrect
+}
diff --git a/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
new file mode 100644
index 00000000000..a845dfabe93
--- /dev/null
+++ b/tests/ui/mismatched_types/generic-mismatch-reporting-issue-116615.stderr
@@ -0,0 +1,97 @@
+error[E0308]: mismatched types
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:6:12
+   |
+LL |     foo(1, 2.);
+   |     --- -  ^^ expected integer, found floating-point number
+   |     |   |
+   |     |   expected all arguments to be this integer type because they need to match the type of this parameter
+   |     arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:1:4
+   |
+LL | fn foo<T>(a: T, b: T) {}
+   |    ^^^ -  ----  ---- this parameter needs to match the integer type of `a`
+   |        |  |
+   |        |  `b` needs to match the integer type of this parameter
+   |        `a` and `b` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:8:5
+   |
+LL |     foo_multi_same("a", "b", false, true, (), 32);
+   |     ^^^^^^^^^^^^^^ ---  ---  -----  ----  -- expected `&str`, found `()`
+   |                    |    |    |      |
+   |                    |    |    |      expected `&str`, found `bool`
+   |                    |    |    expected `&str`, found `bool`
+   |                    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     |     this parameter needs to match the `&str` type of `a` and `b`
+   |                   |  |     `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   |  `c`, `d` and `e` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:10:5
+   |
+LL |     foo_multi_generics("a", "b", "c", true, false, 32, 2.);
+   |     ^^^^^^^^^^^^^^^^^^ ---  ---  ---  ----  -----  --  -- expected integer, found floating-point number
+   |                        |    |    |    |     |      |
+   |                        |    |    |    |     |      expected some other arguments to be an integer type to match the type of this parameter
+   |                        |    |    |    |     expected `&str`, found `bool`
+   |                        |    |    |    expected `&str`, found `bool`
+   |                        |    |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        |    expected some other arguments to be an `&str` type to match the type of this parameter
+   |                        expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:3:4
+   |
+LL | fn foo_multi_generics<S, T>(a: T, b: T, c: T, d: T, e: T, f: S, g: S) {}
+   |    ^^^^^^^^^^^^^^^^^^ -  -  ----  ----  ----  ----  ----  ----  ---- this parameter needs to match the integer type of `f`
+   |                       |  |  |     |     |     |     |     |
+   |                       |  |  |     |     |     |     |     `g` needs to match the integer type of this parameter
+   |                       |  |  |     |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     |     this parameter needs to match the `&str` type of `a`, `b` and `c`
+   |                       |  |  |     |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  |     `d` and `e` need to match the `&str` type of this parameter
+   |                       |  |  `d` and `e` need to match the `&str` type of this parameter
+   |                       |  `a`, `b`, `c`, `d` and `e` all reference this parameter T
+   |                       `f` and `g` all reference this parameter S
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:12:5
+   |
+LL |     foo_multi_same("a", 1, 2, "d", "e", 32);
+   |     ^^^^^^^^^^^^^^ ---  -  -  ---  --- expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  |  |
+   |                    |    |  |  expected some other arguments to be an `&str` type to match the type of this parameter
+   |                    |    |  expected `&str`, found integer
+   |                    |    expected `&str`, found integer
+   |                    expected some other arguments to be an `&str` type to match the type of this parameter
+   |
+note: function defined here
+  --> $DIR/generic-mismatch-reporting-issue-116615.rs:2:4
+   |
+LL | fn foo_multi_same<T>(a: T, b: T, c: T, d: T, e: T, f: i32) {}
+   |    ^^^^^^^^^^^^^^ -  ----  ----  ----  ----  ----  ------
+   |                   |  |     |     |     |     |
+   |                   |  |     |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     |     `b` and `c` need to match the `&str` type of this parameter
+   |                   |  |     |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  |     this parameter needs to match the `&str` type of `a`, `d` and `e`
+   |                   |  `b` and `c` need to match the `&str` type of this parameter
+   |                   `a`, `b`, `c`, `d` and `e` all reference this parameter T
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-1362.rs b/tests/ui/mismatched_types/issue-1362.rs
index 6fd43f50e4d..6fd43f50e4d 100644
--- a/tests/ui/issues/issue-1362.rs
+++ b/tests/ui/mismatched_types/issue-1362.rs
diff --git a/tests/ui/issues/issue-1362.stderr b/tests/ui/mismatched_types/issue-1362.stderr
index 6f6fdff6678..6f6fdff6678 100644
--- a/tests/ui/issues/issue-1362.stderr
+++ b/tests/ui/mismatched_types/issue-1362.stderr
diff --git a/tests/ui/issues/issue-1448-2.rs b/tests/ui/mismatched_types/issue-1448-2.rs
index 829e81b9c24..829e81b9c24 100644
--- a/tests/ui/issues/issue-1448-2.rs
+++ b/tests/ui/mismatched_types/issue-1448-2.rs
diff --git a/tests/ui/issues/issue-1448-2.stderr b/tests/ui/mismatched_types/issue-1448-2.stderr
index a6f1daefe63..a6f1daefe63 100644
--- a/tests/ui/issues/issue-1448-2.stderr
+++ b/tests/ui/mismatched_types/issue-1448-2.stderr
diff --git a/tests/ui/pattern/usefulness/unions.rs b/tests/ui/pattern/usefulness/unions.rs
new file mode 100644
index 00000000000..80a7f36a09a
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.rs
@@ -0,0 +1,35 @@
+fn main() {
+    #[derive(Copy, Clone)]
+    union U8AsBool {
+        n: u8,
+        b: bool,
+    }
+
+    let x = U8AsBool { n: 1 };
+    unsafe {
+        match x {
+            // exhaustive
+            U8AsBool { n: 2 } => {}
+            U8AsBool { b: true } => {}
+            U8AsBool { b: false } => {}
+        }
+        match x {
+            // exhaustive
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 0 } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        match x {
+            //~^ ERROR non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+            U8AsBool { b: true } => {}
+            U8AsBool { n: 1.. } => {}
+        }
+        // Our approach can report duplicate witnesses sometimes.
+        match (x, true) {
+            //~^ ERROR non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+            (U8AsBool { b: true }, true) => {}
+            (U8AsBool { b: false }, true) => {}
+            (U8AsBool { n: 1.. }, true) => {}
+        }
+    }
+}
diff --git a/tests/ui/pattern/usefulness/unions.stderr b/tests/ui/pattern/usefulness/unions.stderr
new file mode 100644
index 00000000000..4b397dc25db
--- /dev/null
+++ b/tests/ui/pattern/usefulness/unions.stderr
@@ -0,0 +1,34 @@
+error[E0004]: non-exhaustive patterns: `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+  --> $DIR/unions.rs:22:15
+   |
+LL |         match x {
+   |               ^ patterns `U8AsBool { n: 0_u8 }` and `U8AsBool { b: false }` not covered
+   |
+note: `U8AsBool` defined here
+  --> $DIR/unions.rs:3:11
+   |
+LL |     union U8AsBool {
+   |           ^^^^^^^^
+   = note: the matched value is of type `U8AsBool`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
+   |
+LL ~             U8AsBool { n: 1.. } => {},
+LL +             U8AsBool { n: 0_u8 } | U8AsBool { b: false } => todo!()
+   |
+
+error[E0004]: non-exhaustive patterns: `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+  --> $DIR/unions.rs:28:15
+   |
+LL |         match (x, true) {
+   |               ^^^^^^^^^ patterns `(U8AsBool { n: 0_u8 }, false)`, `(U8AsBool { b: false }, false)`, `(U8AsBool { n: 0_u8 }, false)` and 1 more not covered
+   |
+   = note: the matched value is of type `(U8AsBool, bool)`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms
+   |
+LL ~             (U8AsBool { n: 1.. }, true) => {},
+LL +             _ => todo!()
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/simd/intrinsic/ptr-cast.rs b/tests/ui/simd/intrinsic/ptr-cast.rs
index 62820346241..0490734b48a 100644
--- a/tests/ui/simd/intrinsic/ptr-cast.rs
+++ b/tests/ui/simd/intrinsic/ptr-cast.rs
@@ -4,7 +4,7 @@
 
 extern "rust-intrinsic" {
     fn simd_cast_ptr<T, U>(x: T) -> U;
-    fn simd_expose_addr<T, U>(x: T) -> U;
+    fn simd_expose_provenance<T, U>(x: T) -> U;
     fn simd_with_exposed_provenance<T, U>(x: T) -> U;
 }
 
@@ -22,7 +22,7 @@ fn main() {
         // change constness and type
         let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs);
 
-        let exposed_addr: V<usize> = simd_expose_addr(const_ptrs);
+        let exposed_addr: V<usize> = simd_expose_provenance(const_ptrs);
 
         let with_exposed_provenance: V<*mut i8> = simd_with_exposed_provenance(exposed_addr);
 
diff --git a/tests/ui/issues/issue-1660.rs b/tests/ui/static/issue-1660.rs
index a114a908313..a114a908313 100644
--- a/tests/ui/issues/issue-1660.rs
+++ b/tests/ui/static/issue-1660.rs