about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-18 22:15:41 +0000
committerbors <bors@rust-lang.org>2024-08-18 22:15:41 +0000
commitd0293c6cf22cb37f04ac90a52d1fc259362acc5b (patch)
treee2b1f96dc847cd00e10873d4aad1fbe2b1dbc026
parent6de928dce9472b864f4e5d590dd7aa2075cb7551 (diff)
parentb1493ba5194fcc5cfe4f6315db288e4e18509110 (diff)
downloadrust-d0293c6cf22cb37f04ac90a52d1fc259362acc5b.tar.gz
rust-d0293c6cf22cb37f04ac90a52d1fc259362acc5b.zip
Auto merge of #125854 - beetrees:zst-arg-abi, r=estebank
Move ZST ABI handling to `rustc_target`

Currently, target specific handling of ZST function call ABI (specifically passing them indirectly instead of ignoring them) is handled in `rustc_ty_utils`, whereas all other target specific function call ABI handling is located in `rustc_target`. This PR moves the ZST handling to `rustc_target` so that all the target-specific function call ABI handling is in one place. In the process of doing so, this PR fixes #125850 by ensuring that ZST arguments are always correctly ignored in the x86-64 `"sysv64"` ABI; any code which would be affected by this fix would have ICEd before this PR. Tests are also added using `#[rustc_abi(debug)]` to ensure this behaviour does not regress.

Fixes #125850
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs13
-rw-r--r--compiler/rustc_target/src/abi/call/powerpc.rs20
-rw-r--r--compiler/rustc_target/src/abi/call/s390x.rs18
-rw-r--r--compiler/rustc_target/src/abi/call/sparc64.rs12
-rw-r--r--compiler/rustc_target/src/abi/call/x86_win64.rs10
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs27
-rw-r--r--src/tools/compiletest/src/command-list.rs5
-rw-r--r--tests/ui/abi/c-zst.other-linux.stderr67
-rw-r--r--tests/ui/abi/c-zst.other.stderr67
-rw-r--r--tests/ui/abi/c-zst.powerpc-linux.stderr78
-rw-r--r--tests/ui/abi/c-zst.rs27
-rw-r--r--tests/ui/abi/c-zst.s390x-linux.stderr78
-rw-r--r--tests/ui/abi/c-zst.sparc64-linux.stderr78
-rw-r--r--tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr78
-rw-r--r--tests/ui/abi/sysv64-zst.rs8
-rw-r--r--tests/ui/abi/sysv64-zst.stderr67
-rw-r--r--tests/ui/abi/win64-zst.other.stderr67
-rw-r--r--tests/ui/abi/win64-zst.rs11
-rw-r--r--tests/ui/abi/win64-zst.windows-gnu.stderr78
19 files changed, 766 insertions, 43 deletions
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 5bfc528dffc..25e4d70945b 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -642,7 +642,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
     pub fn make_indirect(&mut self) {
         match self.mode {
             PassMode::Direct(_) | PassMode::Pair(_, _) => {
-                self.mode = Self::indirect_pass_mode(&self.layout);
+                self.make_indirect_force();
             }
             PassMode::Indirect { attrs: _, meta_attrs: _, on_stack: false } => {
                 // already indirect
@@ -652,6 +652,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
         }
     }
 
+    /// Same as make_indirect, but doesn't check the current `PassMode`.
+    pub fn make_indirect_force(&mut self) {
+        self.mode = Self::indirect_pass_mode(&self.layout);
+    }
+
     /// Pass this argument indirectly, by placing it at a fixed stack offset.
     /// This corresponds to the `byval` LLVM argument attribute.
     /// This is only valid for sized arguments.
@@ -871,10 +876,10 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             }
             "x86_64" => match abi {
                 spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
-                spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self),
+                spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(cx, self),
                 _ => {
                     if cx.target_spec().is_like_windows {
-                        x86_win64::compute_abi_info(self)
+                        x86_win64::compute_abi_info(cx, self)
                     } else {
                         x86_64::compute_abi_info(cx, self)
                     }
@@ -898,7 +903,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "csky" => csky::compute_abi_info(self),
             "mips" | "mips32r6" => mips::compute_abi_info(cx, self),
             "mips64" | "mips64r6" => mips64::compute_abi_info(cx, self),
-            "powerpc" => powerpc::compute_abi_info(self),
+            "powerpc" => powerpc::compute_abi_info(cx, self),
             "powerpc64" => powerpc64::compute_abi_info(cx, self),
             "s390x" => s390x::compute_abi_info(cx, self),
             "msp430" => msp430::compute_abi_info(self),
diff --git a/compiler/rustc_target/src/abi/call/powerpc.rs b/compiler/rustc_target/src/abi/call/powerpc.rs
index 70c32db0a87..cb80d64c943 100644
--- a/compiler/rustc_target/src/abi/call/powerpc.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc.rs
@@ -1,4 +1,5 @@
 use crate::abi::call::{ArgAbi, FnAbi};
+use crate::spec::HasTargetSpec;
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     if ret.layout.is_aggregate() {
@@ -8,7 +9,17 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     }
 }
 
-fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
+    if arg.is_ignore() {
+        // powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
+        if cx.target_spec().os == "linux"
+            && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc")
+            && arg.layout.is_zst()
+        {
+            arg.make_indirect_force();
+        }
+        return;
+    }
     if arg.layout.is_aggregate() {
         arg.make_indirect();
     } else {
@@ -16,15 +27,12 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
     }
 }
 
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+pub fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
     if !fn_abi.ret.is_ignore() {
         classify_ret(&mut fn_abi.ret);
     }
 
     for arg in fn_abi.args.iter_mut() {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(arg);
+        classify_arg(cx, arg);
     }
 }
diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs
index 1a2191082d5..7dcbb3e4a9e 100644
--- a/compiler/rustc_target/src/abi/call/s390x.rs
+++ b/compiler/rustc_target/src/abi/call/s390x.rs
@@ -3,6 +3,7 @@
 
 use crate::abi::call::{ArgAbi, FnAbi, Reg};
 use crate::abi::{HasDataLayout, TyAbiInterface};
+use crate::spec::HasTargetSpec;
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
     if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
@@ -15,12 +16,22 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
 fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !arg.layout.is_sized() {
         // Not touching this...
         return;
     }
+    if arg.is_ignore() {
+        // s390x-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
+        if cx.target_spec().os == "linux"
+            && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc")
+            && arg.layout.is_zst()
+        {
+            arg.make_indirect_force();
+        }
+        return;
+    }
     if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
         arg.extend_integer_width_to(64);
         return;
@@ -46,16 +57,13 @@ where
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !fn_abi.ret.is_ignore() {
         classify_ret(&mut fn_abi.ret);
     }
 
     for arg in fn_abi.args.iter_mut() {
-        if arg.is_ignore() {
-            continue;
-        }
         classify_arg(cx, arg);
     }
 }
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs
index c0952130e04..3b2bf9b3187 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/abi/call/sparc64.rs
@@ -4,6 +4,7 @@ use crate::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, Uniform,
 };
 use crate::abi::{self, HasDataLayout, Scalar, Size, TyAbiInterface, TyAndLayout};
+use crate::spec::HasTargetSpec;
 
 #[derive(Clone, Debug)]
 pub struct Sdata {
@@ -211,7 +212,7 @@ where
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
 where
     Ty: TyAbiInterface<'a, C> + Copy,
-    C: HasDataLayout,
+    C: HasDataLayout + HasTargetSpec,
 {
     if !fn_abi.ret.is_ignore() {
         classify_arg(cx, &mut fn_abi.ret, Size::from_bytes(32));
@@ -219,7 +220,14 @@ where
 
     for arg in fn_abi.args.iter_mut() {
         if arg.is_ignore() {
-            continue;
+            // sparc64-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
+            if cx.target_spec().os == "linux"
+                && matches!(&*cx.target_spec().env, "gnu" | "musl" | "uclibc")
+                && arg.layout.is_zst()
+            {
+                arg.make_indirect_force();
+            }
+            return;
         }
         classify_arg(cx, arg, Size::from_bytes(16));
     }
diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs
index 4e19460bd28..6ca01cf84ea 100644
--- a/compiler/rustc_target/src/abi/call/x86_win64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_win64.rs
@@ -1,9 +1,10 @@
 use crate::abi::call::{ArgAbi, FnAbi, Reg};
 use crate::abi::{Abi, Float, Primitive};
+use crate::spec::HasTargetSpec;
 
 // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
 
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+pub fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
     let fixup = |a: &mut ArgAbi<'_, Ty>| {
         match a.layout.abi {
             Abi::Uninhabited | Abi::Aggregate { sized: false } => {}
@@ -37,6 +38,13 @@ pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
     }
     for arg in fn_abi.args.iter_mut() {
         if arg.is_ignore() {
+            // x86_64-pc-windows-gnu doesn't ignore ZSTs.
+            if cx.target_spec().os == "windows"
+                && cx.target_spec().env == "gnu"
+                && arg.layout.is_zst()
+            {
+                arg.make_indirect_force();
+            }
             continue;
         }
         fixup(arg);
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 34c426f2aa6..7e3c30f2383 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -584,7 +584,7 @@ fn fn_abi_new_uncached<'tcx>(
     let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic);
 
     let mut inputs = sig.inputs();
-    let extra_args = if sig.abi == RustCall {
+    let extra_args = if sig.abi == SpecAbi::RustCall {
         assert!(!sig.c_variadic && extra_args.is_empty());
 
         if let Some(input) = sig.inputs().last() {
@@ -608,18 +608,6 @@ fn fn_abi_new_uncached<'tcx>(
         extra_args
     };
 
-    let target = &cx.tcx.sess.target;
-    let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl" | "uclibc");
-    let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
-    let linux_s390x_gnu_like =
-        target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
-    let linux_sparc64_gnu_like =
-        target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
-    let linux_powerpc_gnu_like =
-        target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
-    use SpecAbi::*;
-    let rust_abi = matches!(sig.abi, RustIntrinsic | Rust | RustCall);
-
     let is_drop_in_place =
         fn_def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::DropInPlace));
 
@@ -659,18 +647,7 @@ fn fn_abi_new_uncached<'tcx>(
         });
 
         if arg.layout.is_zst() {
-            // For some forsaken reason, x86_64-pc-windows-gnu
-            // doesn't ignore zero-sized struct arguments.
-            // The same is true for {s390x,sparc64,powerpc}-unknown-linux-{gnu,musl,uclibc}.
-            if is_return
-                || rust_abi
-                || (!win_x64_gnu
-                    && !linux_s390x_gnu_like
-                    && !linux_sparc64_gnu_like
-                    && !linux_powerpc_gnu_like)
-            {
-                arg.mode = PassMode::Ignore;
-            }
+            arg.mode = PassMode::Ignore;
         }
 
         Ok(arg)
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/command-list.rs
index 50c909793f5..9477c48db0a 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/command-list.rs
@@ -92,10 +92,12 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-nvptx64-nvidia-cuda",
     "ignore-openbsd",
     "ignore-pass",
+    "ignore-powerpc",
     "ignore-remote",
     "ignore-riscv64",
     "ignore-s390x",
     "ignore-sgx",
+    "ignore-sparc64",
     "ignore-spirv",
     "ignore-stable",
     "ignore-stage1",
@@ -123,6 +125,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-x86",
     "ignore-x86_64",
     "ignore-x86_64-apple-darwin",
+    "ignore-x86_64-pc-windows-gnu",
     "ignore-x86_64-unknown-linux-gnu",
     "incremental",
     "known-bug",
@@ -191,7 +194,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "only-msvc",
     "only-nightly",
     "only-nvptx64",
+    "only-powerpc",
     "only-riscv64",
+    "only-s390x",
     "only-sparc",
     "only-sparc64",
     "only-stable",
diff --git a/tests/ui/abi/c-zst.other-linux.stderr b/tests/ui/abi/c-zst.other-linux.stderr
new file mode 100644
index 00000000000..5a656e6ea66
--- /dev/null
+++ b/tests/ui/abi/c-zst.other-linux.stderr
@@ -0,0 +1,67 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Ignore,
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/c-zst.other.stderr b/tests/ui/abi/c-zst.other.stderr
new file mode 100644
index 00000000000..5a656e6ea66
--- /dev/null
+++ b/tests/ui/abi/c-zst.other.stderr
@@ -0,0 +1,67 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Ignore,
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr
new file mode 100644
index 00000000000..ba9738050d8
--- /dev/null
+++ b/tests/ui/abi/c-zst.powerpc-linux.stderr
@@ -0,0 +1,78 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       meta_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/c-zst.rs b/tests/ui/abi/c-zst.rs
new file mode 100644
index 00000000000..0cfd653b37e
--- /dev/null
+++ b/tests/ui/abi/c-zst.rs
@@ -0,0 +1,27 @@
+//@ revisions: other other-linux x86_64-pc-windows-gnu s390x-linux sparc64-linux powerpc-linux
+//@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
+// ZSTs are only not ignored when the target_env is "gnu", "musl" or "uclibc". However, Rust does
+// not currently support any other target_env on these architectures.
+
+// Ignore the ZST revisions
+//@[other] ignore-x86_64-pc-windows-gnu
+//@[other] ignore-linux
+//@[other-linux] only-linux
+//@[other-linux] ignore-s390x
+//@[other-linux] ignore-sparc64
+//@[other-linux] ignore-powerpc
+
+// Pass the ZST indirectly revisions
+//@[x86_64-pc-windows-gnu] only-x86_64-pc-windows-gnu
+//@[s390x-linux] only-s390x
+//@[s390x-linux] only-linux
+//@[sparc64-linux] only-sparc64
+//@[sparc64-linux] only-linux
+//@[powerpc-linux] only-powerpc
+//@[powerpc-linux] only-linux
+
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+
+#[rustc_abi(debug)]
+extern "C" fn pass_zst(_: ()) {} //~ ERROR: fn_abi
diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr
new file mode 100644
index 00000000000..ba9738050d8
--- /dev/null
+++ b/tests/ui/abi/c-zst.s390x-linux.stderr
@@ -0,0 +1,78 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       meta_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr
new file mode 100644
index 00000000000..ba9738050d8
--- /dev/null
+++ b/tests/ui/abi/c-zst.sparc64-linux.stderr
@@ -0,0 +1,78 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       meta_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
new file mode 100644
index 00000000000..ba9738050d8
--- /dev/null
+++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
@@ -0,0 +1,78 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       meta_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: C,
+           can_unwind: false,
+       }
+  --> $DIR/c-zst.rs:27:1
+   |
+LL | extern "C" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/sysv64-zst.rs b/tests/ui/abi/sysv64-zst.rs
new file mode 100644
index 00000000000..6f4497e77a1
--- /dev/null
+++ b/tests/ui/abi/sysv64-zst.rs
@@ -0,0 +1,8 @@
+//@ only-x86_64
+//@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
+
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+
+#[rustc_abi(debug)]
+extern "sysv64" fn pass_zst(_: ()) {} //~ ERROR: fn_abi
diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr
new file mode 100644
index 00000000000..8b0b84dfa06
--- /dev/null
+++ b/tests/ui/abi/sysv64-zst.stderr
@@ -0,0 +1,67 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Ignore,
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: X86_64SysV,
+           can_unwind: false,
+       }
+  --> $DIR/sysv64-zst.rs:8:1
+   |
+LL | extern "sysv64" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/win64-zst.other.stderr b/tests/ui/abi/win64-zst.other.stderr
new file mode 100644
index 00000000000..15db141cb57
--- /dev/null
+++ b/tests/ui/abi/win64-zst.other.stderr
@@ -0,0 +1,67 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Ignore,
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: X86_64Win64,
+           can_unwind: false,
+       }
+  --> $DIR/win64-zst.rs:11:1
+   |
+LL | extern "win64" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/abi/win64-zst.rs b/tests/ui/abi/win64-zst.rs
new file mode 100644
index 00000000000..cae32795e16
--- /dev/null
+++ b/tests/ui/abi/win64-zst.rs
@@ -0,0 +1,11 @@
+//@ only-x86_64
+//@ revisions: other windows-gnu
+//@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
+//@[other] ignore-windows-gnu
+//@[windows-gnu] only-windows-gnu
+
+#![feature(rustc_attrs)]
+#![crate_type = "lib"]
+
+#[rustc_abi(debug)]
+extern "win64" fn pass_zst(_: ()) {} //~ ERROR: fn_abi
diff --git a/tests/ui/abi/win64-zst.windows-gnu.stderr b/tests/ui/abi/win64-zst.windows-gnu.stderr
new file mode 100644
index 00000000000..7773e0aa2b5
--- /dev/null
+++ b/tests/ui/abi/win64-zst.windows-gnu.stderr
@@ -0,0 +1,78 @@
+error: fn_abi_of(pass_zst) = FnAbi {
+           args: [
+               ArgAbi {
+                   layout: TyAndLayout {
+                       ty: (),
+                       layout: Layout {
+                           size: Size(0 bytes),
+                           align: AbiAndPrefAlign {
+                               abi: $SOME_ALIGN,
+                               pref: $SOME_ALIGN,
+                           },
+                           abi: Aggregate {
+                               sized: true,
+                           },
+                           fields: Arbitrary {
+                               offsets: [],
+                               memory_index: [],
+                           },
+                           largest_niche: None,
+                           variants: Single {
+                               index: 0,
+                           },
+                           max_repr_align: None,
+                           unadjusted_abi_align: $SOME_ALIGN,
+                       },
+                   },
+                   mode: Indirect {
+                       attrs: ArgAttributes {
+                           regular: NoAlias | NoCapture | NonNull | NoUndef,
+                           arg_ext: None,
+                           pointee_size: Size(0 bytes),
+                           pointee_align: Some(
+                               Align(1 bytes),
+                           ),
+                       },
+                       meta_attrs: None,
+                       on_stack: false,
+                   },
+               },
+           ],
+           ret: ArgAbi {
+               layout: TyAndLayout {
+                   ty: (),
+                   layout: Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: $SOME_ALIGN,
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: $SOME_ALIGN,
+                   },
+               },
+               mode: Ignore,
+           },
+           c_variadic: false,
+           fixed_count: 1,
+           conv: X86_64Win64,
+           can_unwind: false,
+       }
+  --> $DIR/win64-zst.rs:11:1
+   |
+LL | extern "win64" fn pass_zst(_: ()) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+