diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md new file mode 100644 index 00000000000..da08cde3010 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -0,0 +1,39 @@ +Functions marked as `C-cmse-nonsecure-call` place restrictions on their +inputs and outputs. + +- inputs must fit in the 4 available 32-bit argument registers. Alignment +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). + +Erroneous code example: + +```ignore (only fails on supported targets) +#![feature(abi_c_cmse_nonsecure_call)] + +#[no_mangle] +pub fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, +) -> u32 { + f(1, 2, 3, 4, 5) +} +``` + +Arguments' alignment is respected. In the example below, padding is inserted +so that the `u64` argument is passed in registers r2 and r3. There is then no +room left for the final `f32` argument + +```ignore (only fails on supported targets) +#![feature(abi_c_cmse_nonsecure_call)] + +#[no_mangle] +pub fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, +) -> u32 { + f(1, 2, 3.0) +} +``` diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d13d5e1bca2..2a7bc2501c0 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -536,6 +536,7 @@ E0794: 0794, E0795: 0795, E0796: 0796, E0797: 0797, +E0798: 0798, ); ) } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index b43559f4225..15983394a92 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -58,6 +58,23 @@ 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 = {$plural -> + [false] this argument doesn't + *[true] 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 + .note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers + .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + 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/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 03311fed396..1bb4db9cbcf 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1673,3 +1673,30 @@ 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, + pub plural: bool, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)] +#[note(hir_analysis_note1)] +#[note(hir_analysis_note2)] +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..e99717ce00f --- /dev/null +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -0,0 +1,156 @@ +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; + }; + + match is_valid_cmse_inputs(tcx, fn_sig) { + Ok(Ok(())) => {} + Ok(Err(index)) => { + // fn(x: u32, u32, u32, u16, y: u16) -> u32, + // ^^^^^^ + let span = bare_fn_ty.param_names[index] + .span + .to(bare_fn_ty.decl.inputs[index].span) + .to(bare_fn_ty.decl.inputs.last().unwrap().span); + let plural = bare_fn_ty.param_names.len() - index != 1; + dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural }); + } + Err(layout_err) => { + if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) { + dcx.emit_err(err); + } + } + } + + match is_valid_cmse_output(tcx, fn_sig) { + Ok(true) => {} + Ok(false) => { + let span = bare_fn_ty.decl.output.span(); + dcx.emit_err(errors::CmseCallOutputStackSpill { span }); + } + Err(layout_err) => { + if let Some(err) = cmse_layout_err(layout_err, *bare_fn_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, &'tcx LayoutError<'tcx>> { + let mut span = None; + let mut accum = 0u64; + + for (index, arg_def) in fn_sig.inputs().iter().enumerate() { + 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. exceeds 4 32-bit registers + if accum > 16 { + span = span.or(Some(index)); + } + } + + match span { + None => Ok(Ok(())), + Some(span) => Ok(Err(span)), + } +} + +/// 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> { + 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 { + 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 7d1ab232c71..d6eb1a66902 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; @@ -2378,6 +2379,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); + +struct Test { + f1: extern "C-cmse-nonsecure-call" fn(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, 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..fa68d95218c --- /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, u32, u32, u32) -> u64, + | ^^^^^^^^^ + +error[E0412]: cannot find type `U` in this scope + --> $DIR/generics.rs:15:52 + | +LL | struct Test { + | - similarly named type parameter `T` defined here +LL | f1: extern "C-cmse-nonsecure-call" fn(U, u32, u32, u32) -> u64, + | ^ + | +help: a type parameter with a similar name exists + | +LL | f1: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, + | ~ +help: you might be missing a type parameter + | +LL | struct Test { + | +++ + +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:9 + | +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:9 + | +LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper, 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-on-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs deleted file mode 100644 index 364d0858afb..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ build-pass -//@ 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)] -#![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32) -> u32 { - let non_secure_function = unsafe { - transmute:: u32>( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d) -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs deleted file mode 100644 index c225a26c065..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@ 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)] -#![no_core] -#[lang="sized"] -pub trait Sized { } -#[lang="copy"] -pub trait Copy { } -impl Copy for u32 {} - -extern "rust-intrinsic" { - pub fn transmute(e: T) -> U; -} - -#[no_mangle] -pub fn test(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { - let non_secure_function = unsafe { - transmute::< - usize, - extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32> - ( - 0x10000004, - ) - }; - non_secure_function(a, b, c, d, e) -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr deleted file mode 100644 index a8aced2483e..00000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: :0:0: in function test i32 (i32, i32, i32, i32, i32): call to non-secure function would require passing arguments on stack - -error: aborting due to 1 previous error - 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 new file mode 100644 index 00000000000..083a563bd7b --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.rs @@ -0,0 +1,23 @@ +//@ 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, align(16))] +#[allow(unused)] +pub struct AlignRelevant(u32); + +#[no_mangle] +pub fn test( + f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: 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] +) { +} 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 new file mode 100644 index 00000000000..a5f5e1c3151 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -0,0 +1,43 @@ +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:17:63 + | +LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: 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 + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:18:63 + | +LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), + | ^^^ this argument doesn'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 + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:19:53 + | +LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), + | ^^^ this argument doesn'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 + +error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/params-via-stack.rs:20:58 + | +LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), + | ^^^ this argument doesn'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 + +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]), + | ^^^^^^^^ this argument doesn'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 + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0798`. 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 new file mode 100644 index 00000000000..e6af1d60e77 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -0,0 +1,54 @@ +//@ 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)] +pub struct ReprCU64(u64); + +#[repr(C)] +pub struct ReprCBytes(u8, u8, u8, u8, u8); + +#[repr(C)] +pub struct U64Compound(u32, u32); + +#[repr(C, align(16))] +pub struct ReprCAlign16(u16); + +#[no_mangle] +pub fn test( + 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] +) { +} + +#[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)] +pub union ReprCUnionU64 { + _unused: u64, +} + +#[repr(Rust)] +pub union ReprRustUnionU64 { + _unused: u64, +} + +#[no_mangle] +pub fn test_union( + f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798] + f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ 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 new file mode 100644 index 00000000000..89f7f159d6e --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -0,0 +1,84 @@ +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:35:50 + | +LL | u128: extern "C-cmse-nonsecure-call" fn() -> u128, + | ^^^^ 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers + --> $DIR/return-via-stack.rs:36:50 + | +LL | i128: extern "C-cmse-nonsecure-call" fn() -> i128, + | ^^^^ 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 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: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size + +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 new file mode 100644 index 00000000000..9fda55c2a48 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/via-registers.rs @@ -0,0 +1,53 @@ +//@ build-pass +//@ 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)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[repr(transparent)] +pub struct ReprTransparentStruct { + _marker1: (), + _marker2: (), + field: T, + _marker3: (), +} + +#[repr(transparent)] +pub enum ReprTransparentEnumU64 { + A(u64), +} + +#[repr(C)] +pub struct U32Compound(u16, u16); + +#[no_mangle] +#[allow(improper_ctypes_definitions)] +pub fn params( + f1: extern "C-cmse-nonsecure-call" fn(), + f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32), + 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(ReprTransparentStruct, U32Compound), + f7: extern "C-cmse-nonsecure-call" fn([u32; 4]), +) { +} + +#[no_mangle] +pub fn returns( + f1: extern "C-cmse-nonsecure-call" fn() -> u32, + f2: extern "C-cmse-nonsecure-call" fn() -> u64, + 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() -> ReprTransparentStruct, + f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct>, + f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, + f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound, +) { +}