Skip to content

Commit 87224ba

Browse files
committed
add error messages for C-cmse-nonsecure-entry
1 parent b3a6cd6 commit 87224ba

File tree

9 files changed

+331
-69
lines changed

9 files changed

+331
-69
lines changed

compiler/rustc_hir_analysis/messages.ftl

+9-6
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,21 @@ hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are fo
6161
hir_analysis_cmse_call_generic =
6262
function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
6363
64-
hir_analysis_cmse_call_inputs_stack_spill =
65-
arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
64+
hir_analysis_cmse_entry_generic =
65+
functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
66+
67+
hir_analysis_cmse_inputs_stack_spill =
68+
arguments for `"{$abi_name}"` function too large to pass via registers
6669
.label = {$plural ->
6770
[false] this argument doesn't
6871
*[true] these arguments don't
6972
} 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
73+
.note = functions with the `"{$abi_name}"` ABI must pass all their arguments via the 4 32-bit available argument registers
7174
72-
hir_analysis_cmse_call_output_stack_spill =
73-
return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
75+
hir_analysis_cmse_output_stack_spill =
76+
return value of `"{$abi_name}"` function too large to pass via registers
7477
.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
78+
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
7679
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
7780
7881
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures

compiler/rustc_hir_analysis/src/errors.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1697,23 +1697,25 @@ pub struct InvalidReceiverTy<'tcx> {
16971697
pub struct EffectsWithoutNextSolver;
16981698

16991699
#[derive(Diagnostic)]
1700-
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
1700+
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
17011701
#[note]
1702-
pub struct CmseCallInputsStackSpill {
1702+
pub struct CmseInputsStackSpill {
17031703
#[primary_span]
17041704
#[label]
17051705
pub span: Span,
17061706
pub plural: bool,
1707+
pub abi_name: &'static str,
17071708
}
17081709

17091710
#[derive(Diagnostic)]
1710-
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
1711+
#[diag(hir_analysis_cmse_output_stack_spill, code = E0798)]
17111712
#[note(hir_analysis_note1)]
17121713
#[note(hir_analysis_note2)]
1713-
pub struct CmseCallOutputStackSpill {
1714+
pub struct CmseOutputStackSpill {
17141715
#[primary_span]
17151716
#[label]
17161717
pub span: Span,
1718+
pub abi_name: &'static str,
17171719
}
17181720

17191721
#[derive(Diagnostic)]
@@ -1722,3 +1724,10 @@ pub struct CmseCallGeneric {
17221724
#[primary_span]
17231725
pub span: Span,
17241726
}
1727+
1728+
#[derive(Diagnostic)]
1729+
#[diag(hir_analysis_cmse_entry_generic, code = E0798)]
1730+
pub struct CmseEntryGeneric {
1731+
#[primary_span]
1732+
pub span: Span,
1733+
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs

+89-48
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use rustc_errors::DiagCtxtHandle;
22
use rustc_hir as hir;
33
use rustc_hir::HirId;
4+
use rustc_middle::bug;
45
use rustc_middle::ty::layout::LayoutError;
56
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
6-
use rustc_span::Span;
77
use rustc_target::spec::abi;
88

99
use crate::errors;
@@ -18,49 +18,90 @@ pub fn validate_cmse_abi<'tcx>(
1818
abi: abi::Abi,
1919
fn_sig: ty::PolyFnSig<'tcx>,
2020
) {
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);
21+
let abi_name = abi.name();
22+
23+
match abi {
24+
abi::Abi::CCmseNonSecureCall => {
25+
let hir_node = tcx.hir_node(hir_id);
26+
let hir::Node::Ty(hir::Ty {
27+
span: bare_fn_span,
28+
kind: hir::TyKind::BareFn(bare_fn_ty),
29+
..
30+
}) = hir_node
31+
else {
32+
// might happen when this ABI is used incorrectly. That will be handled elsewhere
33+
return;
34+
};
35+
36+
match is_valid_cmse_inputs(tcx, fn_sig) {
37+
Ok(Ok(())) => {}
38+
Ok(Err(index)) => {
39+
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
40+
// ^^^^^^
41+
let span = bare_fn_ty.param_names[index]
42+
.span
43+
.to(bare_fn_ty.decl.inputs[index].span)
44+
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
45+
let plural = bare_fn_ty.param_names.len() - index != 1;
46+
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name });
47+
}
48+
Err(layout_err) => {
49+
if should_emit_generic_error(abi, layout_err) {
50+
dcx.emit_err(errors::CmseCallGeneric { span: *bare_fn_span });
51+
}
4852
}
4953
}
50-
}
5154

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);
55+
match is_valid_cmse_output(tcx, fn_sig) {
56+
Ok(true) => {}
57+
Ok(false) => {
58+
let span = bare_fn_ty.decl.output.span();
59+
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
60+
}
61+
Err(layout_err) => {
62+
if should_emit_generic_error(abi, layout_err) {
63+
dcx.emit_err(errors::CmseCallGeneric { span: *bare_fn_span });
64+
}
65+
}
66+
};
67+
}
68+
abi::Abi::CCmseNonSecureEntry => {
69+
let hir_node = tcx.hir_node(hir_id);
70+
let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else {
71+
// might happen when this ABI is used incorrectly. That will be handled elsewhere
72+
return;
73+
};
74+
75+
match is_valid_cmse_inputs(tcx, fn_sig) {
76+
Ok(Ok(())) => {}
77+
Ok(Err(index)) => {
78+
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
79+
// ^^^^^^
80+
let span = decl.inputs[index].span.to(decl.inputs.last().unwrap().span);
81+
let plural = decl.inputs.len() - index != 1;
82+
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name });
83+
}
84+
Err(layout_err) => {
85+
if should_emit_generic_error(abi, layout_err) {
86+
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
87+
}
6188
}
6289
}
63-
};
90+
91+
match is_valid_cmse_output(tcx, fn_sig) {
92+
Ok(true) => {}
93+
Ok(false) => {
94+
let span = decl.output.span();
95+
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
96+
}
97+
Err(layout_err) => {
98+
if should_emit_generic_error(abi, layout_err) {
99+
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
100+
}
101+
}
102+
};
103+
}
104+
_ => (),
64105
}
65106
}
66107

@@ -135,22 +176,22 @@ fn is_valid_cmse_output<'tcx>(
135176
Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
136177
}
137178

138-
fn cmse_layout_err<'tcx>(
139-
layout_err: &'tcx LayoutError<'tcx>,
140-
span: Span,
141-
) -> Option<crate::errors::CmseCallGeneric> {
179+
fn should_emit_generic_error<'tcx>(abi: abi::Abi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
142180
use LayoutError::*;
143181

144182
match layout_err {
145183
Unknown(ty) => {
146-
if ty.is_impl_trait() {
147-
None // prevent double reporting of this error
148-
} else {
149-
Some(errors::CmseCallGeneric { span })
184+
match abi {
185+
abi::Abi::CCmseNonSecureCall => {
186+
// prevent double reporting of this error
187+
!ty.is_impl_trait()
188+
}
189+
abi::Abi::CCmseNonSecureEntry => true,
190+
_ => bug!("invalid ABI: {abi}"),
150191
}
151192
}
152193
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
153-
None // not our job to report these
194+
false // not our job to report these
154195
}
155196
}
156197
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
//@ needs-llvm-components: arm
3+
#![feature(cmse_nonsecure_entry, 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+
impl<T: Copy> Wrapper<T> {
15+
extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 {
16+
//~^ ERROR [E0798]
17+
0
18+
}
19+
20+
extern "C-cmse-nonsecure-entry" fn ambient_generic_nested(
21+
//~^ ERROR [E0798]
22+
_: Wrapper<T>,
23+
_: u32,
24+
_: u32,
25+
_: u32,
26+
) -> u64 {
27+
0
28+
}
29+
}
30+
31+
extern "C-cmse-nonsecure-entry" fn introduced_generic<U: Copy>(
32+
//~^ ERROR [E0798]
33+
_: U,
34+
_: u32,
35+
_: u32,
36+
_: u32,
37+
) -> u64 {
38+
0
39+
}
40+
41+
extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 {
42+
//~^ ERROR [E0798]
43+
0
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
2+
--> $DIR/generics.rs:31:1
3+
|
4+
LL | / extern "C-cmse-nonsecure-entry" fn introduced_generic<U: Copy>(
5+
LL | |
6+
LL | | _: U,
7+
LL | | _: u32,
8+
LL | | _: u32,
9+
LL | | _: u32,
10+
LL | | ) -> u64 {
11+
| |________^
12+
13+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
14+
--> $DIR/generics.rs:41:1
15+
|
16+
LL | extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 {
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
20+
--> $DIR/generics.rs:15:5
21+
|
22+
LL | extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
26+
--> $DIR/generics.rs:20:5
27+
|
28+
LL | / extern "C-cmse-nonsecure-entry" fn ambient_generic_nested(
29+
LL | |
30+
LL | | _: Wrapper<T>,
31+
LL | | _: u32,
32+
LL | | _: u32,
33+
LL | | _: u32,
34+
LL | | ) -> u64 {
35+
| |____________^
36+
37+
error: aborting due to 4 previous errors
38+
39+
For more information about this error, try `rustc --explain E0798`.

tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//@ build-fail
21
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
32
//@ needs-llvm-components: arm
43
#![feature(cmse_nonsecure_entry, no_core, lang_items)]
@@ -14,14 +13,14 @@ impl Copy for u32 {}
1413
pub struct AlignRelevant(u32);
1514

1615
#[no_mangle]
17-
pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {}
16+
pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} //~ ERROR [E0798]
1817
#[no_mangle]
19-
pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {}
18+
pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} //~ ERROR [E0798]
2019
#[no_mangle]
21-
pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {}
20+
pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} //~ ERROR [E0798]
2221
#[no_mangle]
23-
pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {}
22+
pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} //~ ERROR [E0798]
2423

2524
#[no_mangle]
2625
#[allow(improper_ctypes_definitions)]
27-
pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {}
26+
pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} //~ ERROR [E0798]
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
1-
error: <unknown>:0:0: in function f1 void (i32, i32, i32, i32, i32, i32): secure entry function requires arguments on stack
1+
error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
2+
--> $DIR/params-via-stack.rs:16:78
3+
|
4+
LL | pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {}
5+
| ^^^^^^^^^^^ these arguments don't fit in the available registers
6+
|
7+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
28

3-
error: aborting due to 1 previous error
9+
error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
10+
--> $DIR/params-via-stack.rs:18:78
11+
|
12+
LL | pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {}
13+
| ^^^ this argument doesn't fit in the available registers
14+
|
15+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
416

17+
error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
18+
--> $DIR/params-via-stack.rs:20:62
19+
|
20+
LL | pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {}
21+
| ^^^ this argument doesn't fit in the available registers
22+
|
23+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
24+
25+
error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
26+
--> $DIR/params-via-stack.rs:22:64
27+
|
28+
LL | pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {}
29+
| ^^^ this argument doesn't fit in the available registers
30+
|
31+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
32+
33+
error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
34+
--> $DIR/params-via-stack.rs:26:46
35+
|
36+
LL | pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {}
37+
| ^^^^^^^^ this argument doesn't fit in the available registers
38+
|
39+
= note: functions with the `"C-cmse-nonsecure-entry"` 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`.

0 commit comments

Comments
 (0)