Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3b20150

Browse files
authoredJul 19, 2024
Rollup merge of #127814 - folkertdev:c-cmse-nonsecure-call-error-messages, r=oli-obk
`C-cmse-nonsecure-call`: improved error messages tracking issue: #81391 issue for the error messages (partially implemented by this PR): #81347 related, in that it also deals with CMSE: #127766 When using the `C-cmse-nonsecure-call` ABI, both the arguments and return value must be passed via registers. Previously, when violating this constraint, an ugly LLVM error would be shown. Now, the rust compiler itself will print a pretty message and link to more information.
2 parents 6ae6f8b + c2894a4 commit 3b20150

File tree

16 files changed

+569
-55
lines changed

16 files changed

+569
-55
lines changed
 
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Functions marked as `C-cmse-nonsecure-call` place restrictions on their
2+
inputs and outputs.
3+
4+
- inputs must fit in the 4 available 32-bit argument registers. Alignment
5+
is relevant.
6+
- outputs must either fit in 4 bytes, or be a foundational type of
7+
size 8 (`i64`, `u64`, `f64`).
8+
- no generics can be used in the signature
9+
10+
For more information,
11+
see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases).
12+
13+
Erroneous code example:
14+
15+
```ignore (only fails on supported targets)
16+
#![feature(abi_c_cmse_nonsecure_call)]
17+
18+
#[no_mangle]
19+
pub fn test(
20+
f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32,
21+
) -> u32 {
22+
f(1, 2, 3, 4, 5)
23+
}
24+
```
25+
26+
Arguments' alignment is respected. In the example below, padding is inserted
27+
so that the `u64` argument is passed in registers r2 and r3. There is then no
28+
room left for the final `f32` argument
29+
30+
```ignore (only fails on supported targets)
31+
#![feature(abi_c_cmse_nonsecure_call)]
32+
33+
#[no_mangle]
34+
pub fn test(
35+
f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32,
36+
) -> u32 {
37+
f(1, 2, 3.0)
38+
}
39+
```

‎compiler/rustc_error_codes/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ E0794: 0794,
536536
E0795: 0795,
537537
E0796: 0796,
538538
E0797: 0797,
539+
E0798: 0798,
539540
);
540541
)
541542
}

‎compiler/rustc_hir_analysis/messages.ftl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,23 @@ hir_analysis_cannot_capture_late_bound_ty =
5858
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
5959
.label = `for<...>` is here
6060
61+
hir_analysis_cmse_call_generic =
62+
function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
63+
64+
hir_analysis_cmse_call_inputs_stack_spill =
65+
arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
66+
.label = {$plural ->
67+
[false] this argument doesn't
68+
*[true] these arguments don't
69+
} fit in the available registers
70+
.note = functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
71+
72+
hir_analysis_cmse_call_output_stack_spill =
73+
return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
74+
.label = this type doesn't fit in the available registers
75+
.note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
76+
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
77+
6178
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
6279
6380
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions

‎compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,3 +1673,30 @@ pub struct InvalidReceiverTy<'tcx> {
16731673
#[note]
16741674
#[help]
16751675
pub struct EffectsWithoutNextSolver;
1676+
1677+
#[derive(Diagnostic)]
1678+
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
1679+
#[note]
1680+
pub struct CmseCallInputsStackSpill {
1681+
#[primary_span]
1682+
#[label]
1683+
pub span: Span,
1684+
pub plural: bool,
1685+
}
1686+
1687+
#[derive(Diagnostic)]
1688+
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
1689+
#[note(hir_analysis_note1)]
1690+
#[note(hir_analysis_note2)]
1691+
pub struct CmseCallOutputStackSpill {
1692+
#[primary_span]
1693+
#[label]
1694+
pub span: Span,
1695+
}
1696+
1697+
#[derive(Diagnostic)]
1698+
#[diag(hir_analysis_cmse_call_generic, code = E0798)]
1699+
pub struct CmseCallGeneric {
1700+
#[primary_span]
1701+
pub span: Span,
1702+
}
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use rustc_errors::DiagCtxtHandle;
2+
use rustc_hir as hir;
3+
use rustc_hir::HirId;
4+
use rustc_middle::ty::layout::LayoutError;
5+
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
6+
use rustc_span::Span;
7+
use rustc_target::spec::abi;
8+
9+
use crate::errors;
10+
11+
/// Check conditions on inputs and outputs that the cmse ABIs impose: arguments and results MUST be
12+
/// returned via registers (i.e. MUST NOT spill to the stack). LLVM will also validate these
13+
/// conditions, but by checking them here rustc can emit nicer error messages.
14+
pub fn validate_cmse_abi<'tcx>(
15+
tcx: TyCtxt<'tcx>,
16+
dcx: DiagCtxtHandle<'_>,
17+
hir_id: HirId,
18+
abi: abi::Abi,
19+
fn_sig: ty::PolyFnSig<'tcx>,
20+
) {
21+
if let abi::Abi::CCmseNonSecureCall = abi {
22+
let hir_node = tcx.hir_node(hir_id);
23+
let hir::Node::Ty(hir::Ty {
24+
span: bare_fn_span,
25+
kind: hir::TyKind::BareFn(bare_fn_ty),
26+
..
27+
}) = hir_node
28+
else {
29+
// might happen when this ABI is used incorrectly. That will be handled elsewhere
30+
return;
31+
};
32+
33+
match is_valid_cmse_inputs(tcx, fn_sig) {
34+
Ok(Ok(())) => {}
35+
Ok(Err(index)) => {
36+
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
37+
// ^^^^^^
38+
let span = bare_fn_ty.param_names[index]
39+
.span
40+
.to(bare_fn_ty.decl.inputs[index].span)
41+
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
42+
let plural = bare_fn_ty.param_names.len() - index != 1;
43+
dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural });
44+
}
45+
Err(layout_err) => {
46+
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
47+
dcx.emit_err(err);
48+
}
49+
}
50+
}
51+
52+
match is_valid_cmse_output(tcx, fn_sig) {
53+
Ok(true) => {}
54+
Ok(false) => {
55+
let span = bare_fn_ty.decl.output.span();
56+
dcx.emit_err(errors::CmseCallOutputStackSpill { span });
57+
}
58+
Err(layout_err) => {
59+
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
60+
dcx.emit_err(err);
61+
}
62+
}
63+
};
64+
}
65+
}
66+
67+
/// Returns whether the inputs will fit into the available registers
68+
fn is_valid_cmse_inputs<'tcx>(
69+
tcx: TyCtxt<'tcx>,
70+
fn_sig: ty::PolyFnSig<'tcx>,
71+
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
72+
let mut span = None;
73+
let mut accum = 0u64;
74+
75+
for (index, arg_def) in fn_sig.inputs().iter().enumerate() {
76+
let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?;
77+
78+
let align = layout.layout.align().abi.bytes();
79+
let size = layout.layout.size().bytes();
80+
81+
accum += size;
82+
accum = accum.next_multiple_of(Ord::max(4, align));
83+
84+
// i.e. exceeds 4 32-bit registers
85+
if accum > 16 {
86+
span = span.or(Some(index));
87+
}
88+
}
89+
90+
match span {
91+
None => Ok(Ok(())),
92+
Some(span) => Ok(Err(span)),
93+
}
94+
}
95+
96+
/// Returns whether the output will fit into the available registers
97+
fn is_valid_cmse_output<'tcx>(
98+
tcx: TyCtxt<'tcx>,
99+
fn_sig: ty::PolyFnSig<'tcx>,
100+
) -> Result<bool, &'tcx LayoutError<'tcx>> {
101+
let mut ret_ty = fn_sig.output().skip_binder();
102+
let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?;
103+
let size = layout.layout.size().bytes();
104+
105+
if size <= 4 {
106+
return Ok(true);
107+
} else if size > 8 {
108+
return Ok(false);
109+
}
110+
111+
// next we need to peel any repr(transparent) layers off
112+
'outer: loop {
113+
let ty::Adt(adt_def, args) = ret_ty.kind() else {
114+
break;
115+
};
116+
117+
if !adt_def.repr().transparent() {
118+
break;
119+
}
120+
121+
// the first field with non-trivial size and alignment must be the data
122+
for variant_def in adt_def.variants() {
123+
for field_def in variant_def.fields.iter() {
124+
let ty = field_def.ty(tcx, args);
125+
let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?;
126+
127+
if !layout.layout.is_1zst() {
128+
ret_ty = ty;
129+
continue 'outer;
130+
}
131+
}
132+
}
133+
}
134+
135+
Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
136+
}
137+
138+
fn cmse_layout_err<'tcx>(
139+
layout_err: &'tcx LayoutError<'tcx>,
140+
span: Span,
141+
) -> Option<crate::errors::CmseCallGeneric> {
142+
use LayoutError::*;
143+
144+
match layout_err {
145+
Unknown(ty) => {
146+
if ty.is_impl_trait() {
147+
None // prevent double reporting of this error
148+
} else {
149+
Some(errors::CmseCallGeneric { span })
150+
}
151+
}
152+
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
153+
None // not our job to report these
154+
}
155+
}
156+
}

‎compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! trait references and bounds.
1515
1616
mod bounds;
17+
mod cmse;
1718
pub mod errors;
1819
pub mod generics;
1920
mod lint;
@@ -2378,6 +2379,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
23782379
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
23792380
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
23802381

2382+
// reject function types that violate cmse ABI requirements
2383+
cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty);
2384+
23812385
// Find any late-bound regions declared in return type that do
23822386
// not appear in the arguments. These are not well-formed.
23832387
//
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
//@ needs-llvm-components: arm
3+
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
4+
#![no_core]
5+
#[lang = "sized"]
6+
pub trait Sized {}
7+
#[lang = "copy"]
8+
pub trait Copy {}
9+
impl Copy for u32 {}
10+
11+
#[repr(C)]
12+
struct Wrapper<T>(T);
13+
14+
struct Test<T: Copy> {
15+
f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, //~ ERROR cannot find type `U` in this scope
16+
//~^ ERROR function pointer types may not have generic parameters
17+
f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
18+
//~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters
19+
f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798]
20+
f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798]
21+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: function pointer types may not have generic parameters
2+
--> $DIR/generics.rs:15:42
3+
|
4+
LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64,
5+
| ^^^^^^^^^
6+
7+
error[E0412]: cannot find type `U` in this scope
8+
--> $DIR/generics.rs:15:52
9+
|
10+
LL | struct Test<T: Copy> {
11+
| - similarly named type parameter `T` defined here
12+
LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64,
13+
| ^
14+
|
15+
help: a type parameter with a similar name exists
16+
|
17+
LL | f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(T, u32, u32, u32) -> u64,
18+
| ~
19+
help: you might be missing a type parameter
20+
|
21+
LL | struct Test<T: Copy, U> {
22+
| +++
23+
24+
error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters
25+
--> $DIR/generics.rs:17:43
26+
|
27+
LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
28+
| ^^^^^^^^^
29+
|
30+
= note: `impl Trait` is only allowed in arguments and return types of functions and methods
31+
32+
error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
33+
--> $DIR/generics.rs:19:9
34+
|
35+
LL | f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64,
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
37+
38+
error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
39+
--> $DIR/generics.rs:20:9
40+
|
41+
LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64,
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43+
44+
error: aborting due to 5 previous errors
45+
46+
Some errors have detailed explanations: E0412, E0562, E0798.
47+
For more information about an error, try `rustc --explain E0412`.

‎tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-registers.rs

Lines changed: 0 additions & 24 deletions
This file was deleted.

‎tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.rs

Lines changed: 0 additions & 27 deletions
This file was deleted.

‎tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-on-stack.stderr

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
//@ needs-llvm-components: arm
3+
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
4+
#![no_core]
5+
#[lang = "sized"]
6+
pub trait Sized {}
7+
#[lang = "copy"]
8+
pub trait Copy {}
9+
impl Copy for u32 {}
10+
11+
#[repr(C, align(16))]
12+
#[allow(unused)]
13+
pub struct AlignRelevant(u32);
14+
15+
#[no_mangle]
16+
pub fn test(
17+
f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32), //~ ERROR [E0798]
18+
f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), //~ ERROR [E0798]
19+
f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32), //~ ERROR [E0798]
20+
f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32), //~ ERROR [E0798]
21+
f5: extern "C-cmse-nonsecure-call" fn([u32; 5]), //~ ERROR [E0798]
22+
) {
23+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
2+
--> $DIR/params-via-stack.rs:17:63
3+
|
4+
LL | f1: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32),
5+
| ^^^^^^^^^^^^^^ these arguments don't fit in the available registers
6+
|
7+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
8+
9+
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
10+
--> $DIR/params-via-stack.rs:18:63
11+
|
12+
LL | f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u16, u16),
13+
| ^^^ this argument doesn't fit in the available registers
14+
|
15+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
16+
17+
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
18+
--> $DIR/params-via-stack.rs:19:53
19+
|
20+
LL | f3: extern "C-cmse-nonsecure-call" fn(u32, u64, u32),
21+
| ^^^ this argument doesn't fit in the available registers
22+
|
23+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
24+
25+
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
26+
--> $DIR/params-via-stack.rs:20:58
27+
|
28+
LL | f4: extern "C-cmse-nonsecure-call" fn(AlignRelevant, u32),
29+
| ^^^ this argument doesn't fit in the available registers
30+
|
31+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
32+
33+
error[E0798]: arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
34+
--> $DIR/params-via-stack.rs:21:43
35+
|
36+
LL | f5: extern "C-cmse-nonsecure-call" fn([u32; 5]),
37+
| ^^^^^^^^ this argument doesn't fit in the available registers
38+
|
39+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
40+
41+
error: aborting due to 5 previous errors
42+
43+
For more information about this error, try `rustc --explain E0798`.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
//@ needs-llvm-components: arm
3+
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items)]
4+
#![no_core]
5+
#[lang = "sized"]
6+
pub trait Sized {}
7+
#[lang = "copy"]
8+
pub trait Copy {}
9+
impl Copy for u32 {}
10+
11+
#[repr(C)]
12+
pub struct ReprCU64(u64);
13+
14+
#[repr(C)]
15+
pub struct ReprCBytes(u8, u8, u8, u8, u8);
16+
17+
#[repr(C)]
18+
pub struct U64Compound(u32, u32);
19+
20+
#[repr(C, align(16))]
21+
pub struct ReprCAlign16(u16);
22+
23+
#[no_mangle]
24+
pub fn test(
25+
f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798]
26+
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798]
27+
f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798]
28+
f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798]
29+
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798]
30+
) {
31+
}
32+
33+
#[allow(improper_ctypes_definitions)]
34+
struct Test {
35+
u128: extern "C-cmse-nonsecure-call" fn() -> u128, //~ ERROR [E0798]
36+
i128: extern "C-cmse-nonsecure-call" fn() -> i128, //~ ERROR [E0798]
37+
}
38+
39+
#[repr(C)]
40+
pub union ReprCUnionU64 {
41+
_unused: u64,
42+
}
43+
44+
#[repr(Rust)]
45+
pub union ReprRustUnionU64 {
46+
_unused: u64,
47+
}
48+
49+
#[no_mangle]
50+
pub fn test_union(
51+
f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64, //~ ERROR [E0798]
52+
f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64, //~ ERROR [E0798]
53+
) {
54+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
2+
--> $DIR/return-via-stack.rs:35:50
3+
|
4+
LL | u128: extern "C-cmse-nonsecure-call" fn() -> u128,
5+
| ^^^^ this type doesn't fit in the available registers
6+
|
7+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
8+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
9+
10+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
11+
--> $DIR/return-via-stack.rs:36:50
12+
|
13+
LL | i128: extern "C-cmse-nonsecure-call" fn() -> i128,
14+
| ^^^^ this type doesn't fit in the available registers
15+
|
16+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
17+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
18+
19+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
20+
--> $DIR/return-via-stack.rs:25:48
21+
|
22+
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprCU64,
23+
| ^^^^^^^^ this type doesn't fit in the available registers
24+
|
25+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
26+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
27+
28+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
29+
--> $DIR/return-via-stack.rs:26:48
30+
|
31+
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCBytes,
32+
| ^^^^^^^^^^ this type doesn't fit in the available registers
33+
|
34+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
35+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
36+
37+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
38+
--> $DIR/return-via-stack.rs:27:48
39+
|
40+
LL | f3: extern "C-cmse-nonsecure-call" fn() -> U64Compound,
41+
| ^^^^^^^^^^^ this type doesn't fit in the available registers
42+
|
43+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
44+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
45+
46+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
47+
--> $DIR/return-via-stack.rs:28:48
48+
|
49+
LL | f4: extern "C-cmse-nonsecure-call" fn() -> ReprCAlign16,
50+
| ^^^^^^^^^^^^ this type doesn't fit in the available registers
51+
|
52+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
53+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
54+
55+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
56+
--> $DIR/return-via-stack.rs:29:48
57+
|
58+
LL | f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 5],
59+
| ^^^^^^^ this type doesn't fit in the available registers
60+
|
61+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
62+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
63+
64+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
65+
--> $DIR/return-via-stack.rs:51:48
66+
|
67+
LL | f1: extern "C-cmse-nonsecure-call" fn() -> ReprRustUnionU64,
68+
| ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
69+
|
70+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
71+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
72+
73+
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
74+
--> $DIR/return-via-stack.rs:52:48
75+
|
76+
LL | f2: extern "C-cmse-nonsecure-call" fn() -> ReprCUnionU64,
77+
| ^^^^^^^^^^^^^ this type doesn't fit in the available registers
78+
|
79+
= note: functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
80+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
81+
82+
error: aborting due to 9 previous errors
83+
84+
For more information about this error, try `rustc --explain E0798`.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//@ build-pass
2+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
3+
//@ needs-llvm-components: arm
4+
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
5+
#![no_core]
6+
#[lang = "sized"]
7+
pub trait Sized {}
8+
#[lang = "copy"]
9+
pub trait Copy {}
10+
impl Copy for u32 {}
11+
12+
#[repr(transparent)]
13+
pub struct ReprTransparentStruct<T> {
14+
_marker1: (),
15+
_marker2: (),
16+
field: T,
17+
_marker3: (),
18+
}
19+
20+
#[repr(transparent)]
21+
pub enum ReprTransparentEnumU64 {
22+
A(u64),
23+
}
24+
25+
#[repr(C)]
26+
pub struct U32Compound(u16, u16);
27+
28+
#[no_mangle]
29+
#[allow(improper_ctypes_definitions)]
30+
pub fn params(
31+
f1: extern "C-cmse-nonsecure-call" fn(),
32+
f2: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32),
33+
f3: extern "C-cmse-nonsecure-call" fn(u64, u64),
34+
f4: extern "C-cmse-nonsecure-call" fn(u128),
35+
f5: extern "C-cmse-nonsecure-call" fn(f64, f32, f32),
36+
f6: extern "C-cmse-nonsecure-call" fn(ReprTransparentStruct<u64>, U32Compound),
37+
f7: extern "C-cmse-nonsecure-call" fn([u32; 4]),
38+
) {
39+
}
40+
41+
#[no_mangle]
42+
pub fn returns(
43+
f1: extern "C-cmse-nonsecure-call" fn() -> u32,
44+
f2: extern "C-cmse-nonsecure-call" fn() -> u64,
45+
f3: extern "C-cmse-nonsecure-call" fn() -> i64,
46+
f4: extern "C-cmse-nonsecure-call" fn() -> f64,
47+
f5: extern "C-cmse-nonsecure-call" fn() -> [u8; 4],
48+
f6: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<u64>,
49+
f7: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentStruct<ReprTransparentStruct<u64>>,
50+
f8: extern "C-cmse-nonsecure-call" fn() -> ReprTransparentEnumU64,
51+
f9: extern "C-cmse-nonsecure-call" fn() -> U32Compound,
52+
) {
53+
}

0 commit comments

Comments
 (0)
Please sign in to comment.