From 50ba821e12f51903aba6902b2b404edbc94011d2 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 15:57:00 +0200 Subject: add rust error message for CMSE stack spill when the `C-cmse-nonsecure-call` ABI is used, arguments and return values must be passed via registers. Failing to do so (i.e. spilling to the stack) causes an LLVM error down the line, but now rustc will properly emit an error a bit earlier in the chain --- .../rustc_error_codes/src/error_codes/E0798.md | 36 ++++++++++++++++++++++ compiler/rustc_error_codes/src/lib.rs | 1 + 2 files changed, 37 insertions(+) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0798.md (limited to 'compiler/rustc_error_codes/src') 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..79ed041004e --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -0,0 +1,36 @@ +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`). + +For more information, +see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). + +Erroneous code example: + +```compile_fail,E0798 +#![feature(abi_c_cmse_nonsecure_call)] + +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 + +```compile_fail,E0798 +#![feature(abi_c_cmse_nonsecure_call)] + +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, ); ) } -- cgit 1.4.1-3-g733a5 From 36d23713fb524589be409392472d78b4b3e20da6 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 18:38:42 +0200 Subject: make function pub in error_codes markdown file the error is only generated for functions that are actually codegen'd --- compiler/rustc_error_codes/src/error_codes/E0798.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_error_codes/src') diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md index 79ed041004e..f63796a67f1 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -14,7 +14,7 @@ Erroneous code example: ```compile_fail,E0798 #![feature(abi_c_cmse_nonsecure_call)] -fn test( +pub fn test( f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32, ) -> u32 { f(1, 2, 3, 4, 5) @@ -28,7 +28,7 @@ room left for the final `f32` argument ```compile_fail,E0798 #![feature(abi_c_cmse_nonsecure_call)] -fn test( +pub fn test( f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, ) -> u32 { f(1, 2, 3.0) -- cgit 1.4.1-3-g733a5 From 1a7960603f60239a5b91c27b3d63e2b87eb09512 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 20:36:55 +0200 Subject: another attempt at fixing the examples in the error codes .md --- compiler/rustc_error_codes/src/error_codes/E0798.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'compiler/rustc_error_codes/src') diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md index f63796a67f1..012c13b96ed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -14,6 +14,7 @@ Erroneous code example: ```compile_fail,E0798 #![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 { @@ -28,6 +29,7 @@ room left for the final `f32` argument ```compile_fail,E0798 #![feature(abi_c_cmse_nonsecure_call)] +#[no_mangle] pub fn test( f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32, ) -> u32 { -- cgit 1.4.1-3-g733a5 From 09b620d179713cceb343dc172d7e5633bfd7a824 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 21:26:21 +0200 Subject: stop running code samples in the error code .md --- compiler/rustc_error_codes/src/error_codes/E0798.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_error_codes/src') diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md index 012c13b96ed..89e6f4d5718 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -11,7 +11,7 @@ see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases). Erroneous code example: -```compile_fail,E0798 +```ignore (only fails on supported targets) #![feature(abi_c_cmse_nonsecure_call)] #[no_mangle] @@ -26,7 +26,7 @@ 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 -```compile_fail,E0798 +```ignore (only fails on supported targets) #![feature(abi_c_cmse_nonsecure_call)] #[no_mangle] -- cgit 1.4.1-3-g733a5 From 7b6373496107807327094ec990d317b98e34fd63 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Jul 2024 16:47:03 +0200 Subject: move CMSE validation to hir_analysis --- .../rustc_error_codes/src/error_codes/E0798.md | 1 + compiler/rustc_hir_analysis/messages.ftl | 13 ++ compiler/rustc_hir_analysis/src/check/check.rs | 7 +- compiler/rustc_hir_analysis/src/errors.rs | 25 ++++ .../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 152 +++++++++++++++++++++ .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 10 +- .../cmse-nonsecure/cmse-nonsecure-call/generics.rs | 21 +++ .../cmse-nonsecure-call/generics.stderr | 47 +++++++ .../cmse-nonsecure-call/params-via-stack.rs | 18 +-- .../cmse-nonsecure-call/params-via-stack.stderr | 65 ++++----- .../cmse-nonsecure-call/return-via-stack.rs | 34 ++--- .../cmse-nonsecure-call/return-via-stack.stderr | 136 ++++++------------ .../cmse-nonsecure-call/via-registers.rs | 31 +---- 13 files changed, 363 insertions(+), 197 deletions(-) create mode 100644 compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr (limited to 'compiler/rustc_error_codes/src') 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> { + 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> { + 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 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); + +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..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, 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: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, 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 { _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, 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, + f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct>, + f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64, + f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound, ) { - f1(); - f2(); - f3(); - f4(); - f5(); - f6(); - f7(); - f8(); } -- cgit 1.4.1-3-g733a5