move CMSE validation to hir_analysis
This commit is contained in:
parent
8a3dd7fb5f
commit
7b63734961
@ -5,6 +5,7 @@ inputs and outputs.
|
|||||||
is relevant.
|
is relevant.
|
||||||
- outputs must either fit in 4 bytes, or be a foundational type of
|
- outputs must either fit in 4 bytes, or be a foundational type of
|
||||||
size 8 (`i64`, `u64`, `f64`).
|
size 8 (`i64`, `u64`, `f64`).
|
||||||
|
- no generics can be used in the signature
|
||||||
|
|
||||||
For more information,
|
For more information,
|
||||||
see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases).
|
see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases).
|
||||||
|
@ -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
|
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
|
||||||
.label = `for<...>` is here
|
.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_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
|
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
|
||||||
|
@ -1287,9 +1287,10 @@ fn check_non_exhaustive<'tcx>(
|
|||||||
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
|
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
|
||||||
});
|
});
|
||||||
|
|
||||||
let non_trivial_fields = field_infos
|
let non_trivial_fields =
|
||||||
.clone()
|
field_infos.clone().filter_map(
|
||||||
.filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
|
|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None },
|
||||||
|
);
|
||||||
let non_trivial_count = non_trivial_fields.clone().count();
|
let non_trivial_count = non_trivial_fields.clone().count();
|
||||||
if non_trivial_count >= 2 {
|
if non_trivial_count >= 2 {
|
||||||
bad_non_zero_sized_fields(
|
bad_non_zero_sized_fields(
|
||||||
|
@ -1682,3 +1682,28 @@ pub struct InvalidReceiverTy<'tcx> {
|
|||||||
#[note]
|
#[note]
|
||||||
#[help]
|
#[help]
|
||||||
pub struct EffectsWithoutNextSolver;
|
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,
|
||||||
|
}
|
||||||
|
152
compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Normal file
152
compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@
|
|||||||
//! trait references and bounds.
|
//! trait references and bounds.
|
||||||
|
|
||||||
mod bounds;
|
mod bounds;
|
||||||
|
mod cmse;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod generics;
|
pub mod generics;
|
||||||
mod lint;
|
mod lint;
|
||||||
@ -1748,7 +1749,11 @@ pub fn lower_path(
|
|||||||
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
|
||||||
let _ = self.prohibit_generic_args(
|
let _ = self.prohibit_generic_args(
|
||||||
path.segments.iter().enumerate().filter_map(|(index, seg)| {
|
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,
|
GenericsArgsErrExtend::DefVariant,
|
||||||
);
|
);
|
||||||
@ -2324,6 +2329,9 @@ pub fn lower_fn_ty(
|
|||||||
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
|
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);
|
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
|
// Find any late-bound regions declared in return type that do
|
||||||
// not appear in the arguments. These are not well-formed.
|
// not appear in the arguments. These are not well-formed.
|
||||||
//
|
//
|
||||||
|
21
tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
Normal file
21
tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
Normal file
@ -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]
|
||||||
|
}
|
47
tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
Normal file
47
tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
Normal file
@ -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`.
|
@ -1,7 +1,6 @@
|
|||||||
//@ build-fail
|
|
||||||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
||||||
//@ needs-llvm-components: arm
|
//@ 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]
|
#![no_core]
|
||||||
#[lang = "sized"]
|
#[lang = "sized"]
|
||||||
pub trait Sized {}
|
pub trait Sized {}
|
||||||
@ -15,15 +14,10 @@ impl Copy for u32 {}
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn test(
|
pub fn test(
|
||||||
f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> 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) -> u32,
|
f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798]
|
||||||
f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32,
|
f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), //~ ERROR [E0798]
|
||||||
f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32,
|
f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), //~ ERROR [E0798]
|
||||||
f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32,
|
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]
|
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,42 @@
|
|||||||
error[E0798]: arguments for `C-cmse-nonsecure-call` function too large to pass via registers
|
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/params-via-stack.rs:24:5
|
--> $DIR/params-via-stack.rs:17:43
|
||||||
|
|
|
|
||||||
LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32,
|
LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32),
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||||
...
|
|
||||||
LL | f1(1, 2, 3, 4, 5);
|
|
||||||
| ^^^^^^^^^^^^^^^^^ but its 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
|
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/params-via-stack.rs:25:5
|
--> $DIR/params-via-stack.rs:18:43
|
||||||
|
|
|
|
||||||
LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16) -> u32,
|
LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16),
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||||
...
|
|
||||||
LL | f2(1, 2, 3, 4, 5);
|
|
||||||
| ^^^^^^^^^^^^^^^^^ but its 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
|
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/params-via-stack.rs:26:5
|
--> $DIR/params-via-stack.rs:19:43
|
||||||
|
|
|
|
||||||
LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32) -> u32,
|
LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32),
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||||
...
|
|
||||||
LL | f3(1, 2, 3);
|
|
||||||
| ^^^^^^^^^^^ but its 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
|
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/params-via-stack.rs:27:5
|
--> $DIR/params-via-stack.rs:20:43
|
||||||
|
|
|
|
||||||
LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32) -> u32,
|
LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32),
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||||
...
|
|
||||||
LL | f4(AlignRelevant(1), 2);
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ but its 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
|
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/params-via-stack.rs:28:5
|
--> $DIR/params-via-stack.rs:21:43
|
||||||
|
|
|
|
||||||
LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]) -> u32,
|
LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]),
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^ these arguments don't fit in the available registers
|
||||||
...
|
|
||||||
LL | f5([0xAA; 5]);
|
|
||||||
| ^^^^^^^^^^^^^ but its 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
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
//@ build-fail
|
|
||||||
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
|
||||||
//@ needs-llvm-components: arm
|
//@ 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]
|
#![no_core]
|
||||||
#[lang = "sized"]
|
#[lang = "sized"]
|
||||||
pub trait Sized {}
|
pub trait Sized {}
|
||||||
@ -23,21 +22,18 @@ impl Copy for u32 {}
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn test(
|
pub fn test(
|
||||||
f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
|
f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798]
|
||||||
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
|
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798]
|
||||||
f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
|
f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798]
|
||||||
f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
|
f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798]
|
||||||
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
|
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798]
|
||||||
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(); //~ ERROR [E0798]
|
}
|
||||||
f2(); //~ ERROR [E0798]
|
|
||||||
f3(); //~ ERROR [E0798]
|
#[allow(improper_ctypes_definitions)]
|
||||||
f4(); //~ ERROR [E0798]
|
struct Test {
|
||||||
f5(); //~ ERROR [E0798]
|
u128: extern "C-cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798]
|
||||||
f6(); //~ ERROR [E0798]
|
i128: extern "C-cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798]
|
||||||
f7(); //~ ERROR [E0798]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -52,9 +48,7 @@ pub union ReprRustUnionU64 {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn test_union(
|
pub fn test_union(
|
||||||
f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ WARNING [improper_ctypes_definitions]
|
f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798]
|
||||||
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
|
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798]
|
||||||
) {
|
) {
|
||||||
f1(); //~ ERROR [E0798]
|
|
||||||
f2(); //~ ERROR [E0798]
|
|
||||||
}
|
}
|
||||||
|
@ -1,133 +1,75 @@
|
|||||||
warning: `extern` fn uses type `u128`, which is not FFI-safe
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:31:9
|
--> $DIR/return-via-stack.rs:35:50
|
||||||
|
|
|
|
||||||
LL | f6: extern "C-cmse-nonsecure-call" fn() -> u128,
|
LL | u128: extern "C-cmse-nonsecure-call" fn() -> u128,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
| ^^^^ 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
|
||||||
= note: `#[warn(improper_ctypes_definitions)]` on by default
|
|
||||||
|
|
||||||
warning: `extern` fn uses type `i128`, which is not FFI-safe
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:32:9
|
--> $DIR/return-via-stack.rs:36:50
|
||||||
|
|
|
|
||||||
LL | f7: extern "C-cmse-nonsecure-call" fn() -> i128,
|
LL | i128: extern "C-cmse-nonsecure-call" fn() -> i128,
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
| ^^^^ 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:55:9
|
--> $DIR/return-via-stack.rs:25:48
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
|
|
||||||
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
|
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f1();
|
|
||||||
| ^^^^ 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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:35:5
|
--> $DIR/return-via-stack.rs:26:48
|
||||||
|
|
|
|
||||||
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
|
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f2();
|
|
||||||
| ^^^^ 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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:36:5
|
--> $DIR/return-via-stack.rs:27:48
|
||||||
|
|
|
|
||||||
LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
|
LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f3();
|
|
||||||
| ^^^^ 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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:37:5
|
--> $DIR/return-via-stack.rs:28:48
|
||||||
|
|
|
|
||||||
LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
|
LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f4();
|
|
||||||
| ^^^^ 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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:38:5
|
--> $DIR/return-via-stack.rs:29:48
|
||||||
|
|
|
|
||||||
LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
|
LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:39:5
|
--> $DIR/return-via-stack.rs:51:48
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
|
||||||
= 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
|
|
||||||
|
|
|
|
||||||
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64,
|
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f1();
|
|
||||||
| ^^^^ 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
|
= 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
|
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||||
--> $DIR/return-via-stack.rs:59:5
|
--> $DIR/return-via-stack.rs:52:48
|
||||||
|
|
|
|
||||||
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
|
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
|
||||||
| -- this function uses the `C-cmse-nonsecure-call` ABI
|
| ^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
||||||
...
|
|
||||||
LL | f2();
|
|
||||||
| ^^^^ 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
|
= 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`.
|
For more information about this error, try `rustc --explain E0798`.
|
||||||
|
@ -10,10 +10,10 @@ pub trait Copy {}
|
|||||||
impl Copy for u32 {}
|
impl Copy for u32 {}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct ReprTransparentStructU64 {
|
pub struct ReprTransparentStruct<T> {
|
||||||
_marker1: (),
|
_marker1: (),
|
||||||
_marker2: (),
|
_marker2: (),
|
||||||
field: u64,
|
field: T,
|
||||||
_marker3: (),
|
_marker3: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,19 +33,9 @@ pub fn params(
|
|||||||
f3: extern "C-cmse-nonsecure-call" fn(u64, u64),
|
f3: extern "C-cmse-nonsecure-call" fn(u64, u64),
|
||||||
f4: extern "C-cmse-nonsecure-call" fn(u128),
|
f4: extern "C-cmse-nonsecure-call" fn(u128),
|
||||||
f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32),
|
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]),
|
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]
|
#[no_mangle]
|
||||||
@ -55,16 +45,9 @@ pub fn returns(
|
|||||||
f3: extern "C-cmse-nonsecure-call" fn() -> i64,
|
f3: extern "C-cmse-nonsecure-call" fn() -> i64,
|
||||||
f4: extern "C-cmse-nonsecure-call" fn() -> f64,
|
f4: extern "C-cmse-nonsecure-call" fn() -> f64,
|
||||||
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4],
|
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4],
|
||||||
f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStructU64,
|
f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<u64>,
|
||||||
f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64,
|
f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<ReprTransparentStruct<u64>>,
|
||||||
f8: extern "C-cmse-nonsecure-call" fn() -> U32Compound,
|
f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64,
|
||||||
|
f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound,
|
||||||
) {
|
) {
|
||||||
f1();
|
|
||||||
f2();
|
|
||||||
f3();
|
|
||||||
f4();
|
|
||||||
f5();
|
|
||||||
f6();
|
|
||||||
f7();
|
|
||||||
f8();
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user