about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert <folkert@folkertdev.nl>2024-07-17 16:47:03 +0200
committerFolkert <folkert@folkertdev.nl>2024-07-18 12:42:40 +0200
commit7b6373496107807327094ec990d317b98e34fd63 (patch)
treec894ca9f62ed0b0eb2e4fa26fe0c24e6ea2d0cbe
parent8a3dd7fb5f9e2c3b6c8411e59ed7fa8d674c5a91 (diff)
downloadrust-7b6373496107807327094ec990d317b98e34fd63.tar.gz
rust-7b6373496107807327094ec990d317b98e34fd63.zip
move CMSE validation to hir_analysis
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0798.md1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl13
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs152
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs10
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs21
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr47
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs18
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr65
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs34
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr136
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs31
13 files changed, 363 insertions, 197 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md
index 89e6f4d5718..da08cde3010 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0798.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0798.md
@@ -5,6 +5,7 @@ inputs and outputs.
 is relevant.
 - outputs must either fit in 4 bytes, or be a foundational type of
 size 8 (`i64`, `u64`, `f64`).
+- no generics can be used in the signature
 
 For more information,
 see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases).
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 24c5377a3b1..83618041133 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -58,6 +58,19 @@ hir_analysis_cannot_capture_late_bound_ty =
 hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
     .label = `for<...>` is here
 
+hir_analysis_cmse_call_generic =
+    function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
+
+hir_analysis_cmse_call_inputs_stack_spill =
+    arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+    .label = these arguments don't fit in the available registers
+    .note = functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
+
+hir_analysis_cmse_call_output_stack_spill =
+    return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+    .label = this type doesn't fit in the available registers
+    .note = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
+
 hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
 
 hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index bf8ef18c04f..aa302e4c25f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1287,9 +1287,10 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
         (span, trivial, check_non_exhaustive(tcx, ty).break_value())
     });
 
-    let non_trivial_fields = field_infos
-        .clone()
-        .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
+    let non_trivial_fields =
+        field_infos.clone().filter_map(
+            |(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None },
+        );
     let non_trivial_count = non_trivial_fields.clone().count();
     if non_trivial_count >= 2 {
         bad_non_zero_sized_fields(
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 0ee87a13e9e..f6783364f16 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1682,3 +1682,28 @@ pub struct InvalidReceiverTy<'tcx> {
 #[note]
 #[help]
 pub struct EffectsWithoutNextSolver;
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
+#[note]
+pub struct CmseCallInputsStackSpill {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
+#[note]
+pub struct CmseCallOutputStackSpill {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cmse_call_generic, code = E0798)]
+pub struct CmseCallGeneric {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
new file mode 100644
index 00000000000..8980173f738
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
@@ -0,0 +1,152 @@
+use rustc_errors::DiagCtxtHandle;
+use rustc_hir as hir;
+use rustc_hir::HirId;
+use rustc_middle::ty::layout::LayoutError;
+use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+use rustc_span::Span;
+use rustc_target::spec::abi;
+
+use crate::errors;
+
+/// Check conditions on inputs and outputs that the cmse ABIs impose: arguments and results MUST be
+/// returned via registers (i.e. MUST NOT spill to the stack). LLVM will also validate these
+/// conditions, but by checking them here rustc can emit nicer error messages.
+pub fn validate_cmse_abi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    dcx: &DiagCtxtHandle<'_>,
+    hir_id: HirId,
+    abi: abi::Abi,
+    fn_sig: ty::PolyFnSig<'tcx>,
+) {
+    if let abi::Abi::CCmseNonSecureCall = abi {
+        let hir_node = tcx.hir_node(hir_id);
+        let hir::Node::Ty(hir::Ty {
+            span: bare_fn_span,
+            kind: hir::TyKind::BareFn(bare_fn_ty),
+            ..
+        }) = hir_node
+        else {
+            // might happen when this ABI is used incorrectly. That will be handled elsewhere
+            return;
+        };
+
+        // fn(u32, u32, u32, u16, u16) -> u32,
+        //    ^^^^^^^^^^^^^^^^^^^^^^^     ^^^
+        let output_span = bare_fn_ty.decl.output.span();
+        let inputs_span = match (
+            bare_fn_ty.param_names.first(),
+            bare_fn_ty.decl.inputs.first(),
+            bare_fn_ty.decl.inputs.last(),
+        ) {
+            (Some(ident), Some(ty1), Some(ty2)) => ident.span.to(ty1.span).to(ty2.span),
+            _ => *bare_fn_span,
+        };
+
+        match is_valid_cmse_inputs(tcx, fn_sig) {
+            Ok(true) => {}
+            Ok(false) => {
+                dcx.emit_err(errors::CmseCallInputsStackSpill { span: inputs_span });
+            }
+            Err(layout_err) => {
+                if let Some(err) = cmse_layout_err(layout_err, inputs_span) {
+                    dcx.emit_err(err);
+                }
+            }
+        }
+
+        match is_valid_cmse_output(tcx, fn_sig) {
+            Ok(true) => {}
+            Ok(false) => {
+                dcx.emit_err(errors::CmseCallOutputStackSpill { span: output_span });
+            }
+            Err(layout_err) => {
+                if let Some(err) = cmse_layout_err(layout_err, output_span) {
+                    dcx.emit_err(err);
+                }
+            }
+        };
+    }
+}
+
+/// Returns whether the inputs will fit into the available registers
+fn is_valid_cmse_inputs<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: ty::PolyFnSig<'tcx>,
+) -> Result<bool, &'tcx LayoutError<'tcx>> {
+    let mut accum = 0u64;
+
+    for arg_def in fn_sig.inputs().iter() {
+        let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?;
+
+        let align = layout.layout.align().abi.bytes();
+        let size = layout.layout.size().bytes();
+
+        accum += size;
+        accum = accum.next_multiple_of(Ord::max(4, align));
+    }
+
+    // i.e. 4 32-bit registers
+    Ok(accum <= 16)
+}
+
+/// Returns whether the output will fit into the available registers
+fn is_valid_cmse_output<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_sig: ty::PolyFnSig<'tcx>,
+) -> Result<bool, &'tcx LayoutError<'tcx>> {
+    let mut ret_ty = fn_sig.output().skip_binder();
+    let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?;
+    let size = layout.layout.size().bytes();
+
+    if size <= 4 {
+        return Ok(true);
+    } else if size > 8 {
+        return Ok(false);
+    }
+
+    // next we need to peel any repr(transparent) layers off
+    'outer: loop {
+        let ty::Adt(adt_def, args) = ret_ty.kind() else {
+            break;
+        };
+
+        if !adt_def.repr().transparent() {
+            break;
+        }
+
+        // the first field with non-trivial size and alignment must be the data
+        for variant_def in adt_def.variants() {
+            for field_def in variant_def.fields.iter() {
+                let ty = field_def.ty(tcx, args);
+                let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?;
+
+                if !layout.layout.is_1zst() {
+                    ret_ty = ty;
+                    continue 'outer;
+                }
+            }
+        }
+    }
+
+    Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
+}
+
+fn cmse_layout_err<'tcx>(
+    layout_err: &'tcx LayoutError<'tcx>,
+    span: Span,
+) -> Option<crate::errors::CmseCallGeneric> {
+    use LayoutError::*;
+
+    match layout_err {
+        Unknown(ty) => {
+            if ty.is_impl_trait() {
+                None // prevent double reporting of this error
+            } else {
+                Some(errors::CmseCallGeneric { span })
+            }
+        }
+        SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
+            None // not our job to report these
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index a665306f2c6..5a98e4d79bb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -14,6 +14,7 @@
 //! trait references and bounds.
 
 mod bounds;
+mod cmse;
 pub mod errors;
 pub mod generics;
 mod lint;
@@ -1748,7 +1749,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
                 let _ = self.prohibit_generic_args(
                     path.segments.iter().enumerate().filter_map(|(index, seg)| {
-                        if !indices.contains(&index) { Some(seg) } else { None }
+                        if !indices.contains(&index) {
+                            Some(seg)
+                        } else {
+                            None
+                        }
                     }),
                     GenericsArgsErrExtend::DefVariant,
                 );
@@ -2324,6 +2329,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
+        // reject function types that violate cmse ABI requirements
+        cmse::validate_cmse_abi(self.tcx(), &self.dcx(), hir_id, abi, bare_fn_ty);
+
         // Find any late-bound regions declared in return type that do
         // not appear in the arguments. These are not well-formed.
         //
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
new file mode 100644
index 00000000000..e6b0bf3e686
--- /dev/null
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+//@ needs-llvm-components: arm
+#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+#[lang = "copy"]
+pub trait Copy {}
+impl Copy for u32 {}
+
+#[repr(C)]
+struct Wrapper<T>(T);
+
+struct Test<T: Copy> {
+    f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, //~ ERROR cannot find type `U` in this scope
+    //~^ ERROR function pointer types may not have generic parameters
+    f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
+    //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters
+    f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798]
+    f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798]
+}
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
new file mode 100644
index 00000000000..b255d261938
--- /dev/null
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
@@ -0,0 +1,47 @@
+error: function pointer types may not have generic parameters
+  --> $DIR/generics.rs:15:42
+   |
+LL |     f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64,
+   |                                          ^^^^^^^^^
+
+error[E0412]: cannot find type `U` in this scope
+  --> $DIR/generics.rs:15:52
+   |
+LL | struct Test<T: Copy> {
+   |             - similarly named type parameter `T` defined here
+LL |     f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64,
+   |                                                    ^
+   |
+help: a type parameter with a similar name exists
+   |
+LL |     f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(T, u32, u32, u32) -> u64,
+   |                                                    ~
+help: you might be missing a type parameter
+   |
+LL | struct Test<T: Copy, U> {
+   |                    +++
+
+error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters
+  --> $DIR/generics.rs:17:43
+   |
+LL |     f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
+   |                                           ^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
+error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
+  --> $DIR/generics.rs:19:43
+   |
+LL |     f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64,
+   |                                           ^^^^^^^^^^^^^^^^
+
+error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
+  --> $DIR/generics.rs:20:43
+   |
+LL |     f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64,
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0412, E0562, E0798.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs
index a4cc74f716f..f8ef4419921 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs
@@ -1,7 +1,6 @@
-//@ build-fail
 //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 //@ needs-llvm-components: arm
-#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
+#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
 #![no_core]
 #[lang = "sized"]
 pub trait Sized {}
@@ -15,15 +14,10 @@ pub struct AlignRelevant(u32);
 
 #[no_mangle]
 pub fn test(
-    f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32,
-    f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32,
-    f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32,
-    f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32,
-    f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32,
+    f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32), //~ ERROR [E0798]
+    f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798]
+    f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32),           //~ ERROR [E0798]
+    f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32),      //~ ERROR [E0798]
+    f5: extern "C-cmse-nonsecure-call" fn([u32; 5]),                //~ ERROR [E0798]
 ) {
-    f1(1, 2, 3, 4, 5); //~ ERROR [E0798]
-    f2(1, 2, 3, 4, 5); //~ ERROR [E0798]
-    f3(1, 2, 3); //~ ERROR [E0798]
-    f4(AlignRelevant(1), 2); //~ ERROR [E0798]
-    f5([0xAA; 5]); //~ ERROR [E0798]
 }
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr
index b161c90d01a..499122ab2c5 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr
@@ -1,57 +1,42 @@
-error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/params-via-stack.rs:24:5
+error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/params-via-stack.rs:17:43
    |
-LL |     f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f1(1, 2, 3, 4, 5);
-   |     ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers
+LL |     f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32),
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
 
-error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/params-via-stack.rs:25:5
+error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/params-via-stack.rs:18:43
    |
-LL |     f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f2(1, 2, 3, 4, 5);
-   |     ^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers
+LL |     f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16),
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
 
-error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/params-via-stack.rs:26:5
+error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/params-via-stack.rs:19:43
    |
-LL |     f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f3(1, 2, 3);
-   |     ^^^^^^^^^^^ but its arguments don't fit in the available registers
+LL |     f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32),
+   |                                           ^^^^^^^^^^^^^ these arguments don't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
 
-error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/params-via-stack.rs:27:5
+error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/params-via-stack.rs:20:43
    |
-LL |     f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f4(AlignRelevant(1), 2);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ but its arguments don't fit in the available registers
+LL |     f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32),
+   |                                           ^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
 
-error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/params-via-stack.rs:28:5
+error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/params-via-stack.rs:21:43
    |
-LL |     f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f5([0xAA; 5]);
-   |     ^^^^^^^^^^^^^ but its arguments don't fit in the available registers
+LL |     f5: extern "C-cmse-nonsecure-call" fn([u32; 5]),
+   |                                           ^^^^^^^^ these arguments don't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass all their arguments via the 4 32-bit available argument registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs
index 2ea69327392..e6af1d60e77 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs
@@ -1,7 +1,6 @@
-//@ build-fail
 //@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
 //@ needs-llvm-components: arm
-#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
+#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
 #![no_core]
 #[lang = "sized"]
 pub trait Sized {}
@@ -23,21 +22,18 @@ pub struct ReprCAlign16(u16);
 
 #[no_mangle]
 pub fn test(
-    f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
-    f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
-    f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
-    f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
-    f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
-    f6: extern "C-cmse-nonsecure-call" fn() -> u128, //~ WARNING [improper_ctypes_definitions]
-    f7: extern "C-cmse-nonsecure-call" fn() -> i128, //~ WARNING [improper_ctypes_definitions]
+    f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798]
+    f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798]
+    f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798]
+    f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798]
+    f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],  //~ ERROR [E0798]
 ) {
-    f1(); //~ ERROR [E0798]
-    f2(); //~ ERROR [E0798]
-    f3(); //~ ERROR [E0798]
-    f4(); //~ ERROR [E0798]
-    f5(); //~ ERROR [E0798]
-    f6(); //~ ERROR [E0798]
-    f7(); //~ ERROR [E0798]
+}
+
+#[allow(improper_ctypes_definitions)]
+struct Test {
+    u128: extern "C-cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798]
+    i128: extern "C-cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798]
 }
 
 #[repr(C)]
@@ -52,9 +48,7 @@ pub union ReprRustUnionU64 {
 
 #[no_mangle]
 pub fn test_union(
-    f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ WARNING [improper_ctypes_definitions]
-    f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
+    f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798]
+    f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,    //~ ERROR [E0798]
 ) {
-    f1(); //~ ERROR [E0798]
-    f2(); //~ ERROR [E0798]
 }
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr
index 99dc7ad4a9f..c8984e3c0d9 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr
@@ -1,133 +1,75 @@
-warning: `extern` fn uses type `u128`, which is not FFI-safe
-  --> $DIR/return-via-stack.rs:31:9
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:35:50
    |
-LL |     f6: extern "C-cmse-nonsecure-call" fn() -> u128,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     u128: extern "C-cmse-nonsecure-call" fn() -> u128,
+   |                                                  ^^^^ this type doesn't fit in the available registers
    |
-   = note: 128-bit integers don't currently have a known stable ABI
-   = note: `#[warn(improper_ctypes_definitions)]` on by default
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-warning: `extern` fn uses type `i128`, which is not FFI-safe
-  --> $DIR/return-via-stack.rs:32:9
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:36:50
    |
-LL |     f7: extern "C-cmse-nonsecure-call" fn() -> i128,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
+LL |     i128: extern "C-cmse-nonsecure-call" fn() -> i128,
+   |                                                  ^^^^ this type doesn't fit in the available registers
    |
-   = note: 128-bit integers don't currently have a known stable ABI
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-warning: `extern` fn uses type `ReprRustUnionU64`, which is not FFI-safe
-  --> $DIR/return-via-stack.rs:55:9
-   |
-LL |     f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64,
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
-   |
-   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
-   = note: this union has unspecified layout
-note: the type is defined here
-  --> $DIR/return-via-stack.rs:49:1
-   |
-LL | pub union ReprRustUnionU64 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:34:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:25:48
    |
 LL |     f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f1();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:35:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:26:48
    |
 LL |     f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f2();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:36:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:27:48
    |
 LL |     f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f3();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:37:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:28:48
    |
 LL |     f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f4();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:38:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:29:48
    |
 LL |     f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f5();
-   |     ^^^^ but its return value doesn't fit in the available registers
-   |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
-
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:39:5
-   |
-LL |     f6: extern "C-cmse-nonsecure-call" fn() -> u128,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f6();
-   |     ^^^^ but its return value doesn't fit in the available registers
-   |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
-
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:40:5
-   |
-LL |     f7: extern "C-cmse-nonsecure-call" fn() -> i128,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f7();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:58:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:51:48
    |
 LL |     f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f1();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error[E0798]: return value of `C-cmse-nonsecure-call` function too large to pass via registers
-  --> $DIR/return-via-stack.rs:59:5
+error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
+  --> $DIR/return-via-stack.rs:52:48
    |
 LL |     f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
-   |     -- this function uses the `C-cmse-nonsecure-call` ABI
-...
-LL |     f2();
-   |     ^^^^ but its return value doesn't fit in the available registers
+   |                                                ^^^^^^^^^^^^^ this type doesn't fit in the available registers
    |
-   = note: functions with the `C-cmse-nonsecure-call` ABI must pass their result via the available return registers
+   = note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
 
-error: aborting due to 9 previous errors; 3 warnings emitted
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0798`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs
index 91aadd4fe1d..9fda55c2a48 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs
@@ -10,10 +10,10 @@ pub trait Copy {}
 impl Copy for u32 {}
 
 #[repr(transparent)]
-pub struct ReprTransparentStructU64 {
+pub struct ReprTransparentStruct<T> {
     _marker1: (),
     _marker2: (),
-    field: u64,
+    field: T,
     _marker3: (),
 }
 
@@ -33,19 +33,9 @@ pub fn params(
     f3: extern "C-cmse-nonsecure-call" fn(u64, u64),
     f4: extern "C-cmse-nonsecure-call" fn(u128),
     f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32),
-    f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStructU64, U32Compound),
+    f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStruct<u64>, U32Compound),
     f7: extern "C-cmse-nonsecure-call" fn([u32; 4]),
 ) {
-    f1();
-    f2(1, 2, 3, 4);
-    f3(1, 2);
-    f4(1);
-    f5(1.0, 2.0, 3.0);
-    f6(
-        ReprTransparentStructU64 { _marker1: (), _marker2: (), field: 1, _marker3: () },
-        U32Compound(2, 3),
-    );
-    f7([0xDEADBEEF; 4]);
 }
 
 #[no_mangle]
@@ -55,16 +45,9 @@ pub fn returns(
     f3: extern "C-cmse-nonsecure-call" fn() -> i64,
     f4: extern "C-cmse-nonsecure-call" fn() -> f64,
     f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4],
-    f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStructU64,
-    f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64,
-    f8: extern "C-cmse-nonsecure-call" fn() -> U32Compound,
+    f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<u64>,
+    f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<ReprTransparentStruct<u64>>,
+    f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64,
+    f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound,
 ) {
-    f1();
-    f2();
-    f3();
-    f4();
-    f5();
-    f6();
-    f7();
-    f8();
 }