Skip to content

Commit e71d2c3

Browse files
committed
improve error messages for C-cmse-nonsecure-entry functions
1 parent 702987f commit e71d2c3

14 files changed

+601
-99
lines changed

compiler/rustc_hir_analysis/messages.ftl

+9-6
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,21 @@ hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are fo
6868
hir_analysis_cmse_call_generic =
6969
function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
7070
71-
hir_analysis_cmse_call_inputs_stack_spill =
72-
arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
71+
hir_analysis_cmse_entry_generic =
72+
functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
73+
74+
hir_analysis_cmse_inputs_stack_spill =
75+
arguments for `"{$abi_name}"` function too large to pass via registers
7376
.label = {$plural ->
7477
[false] this argument doesn't
7578
*[true] these arguments don't
7679
} fit in the available registers
77-
.note = functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
80+
.note = functions with the `"{$abi_name}"` ABI must pass all their arguments via the 4 32-bit available argument registers
7881
79-
hir_analysis_cmse_call_output_stack_spill =
80-
return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
82+
hir_analysis_cmse_output_stack_spill =
83+
return value of `"{$abi_name}"` function too large to pass via registers
8184
.label = this type doesn't fit in the available registers
82-
.note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
85+
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
8386
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
8487
8588
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
@@ -1669,23 +1669,25 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
16691669
pub(crate) struct EffectsWithoutNextSolver;
16701670

16711671
#[derive(Diagnostic)]
1672-
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
1672+
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
16731673
#[note]
1674-
pub(crate) struct CmseCallInputsStackSpill {
1674+
pub(crate) struct CmseInputsStackSpill {
16751675
#[primary_span]
16761676
#[label]
16771677
pub span: Span,
16781678
pub plural: bool,
1679+
pub abi_name: &'static str,
16791680
}
16801681

16811682
#[derive(Diagnostic)]
1682-
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
1683+
#[diag(hir_analysis_cmse_output_stack_spill, code = E0798)]
16831684
#[note(hir_analysis_note1)]
16841685
#[note(hir_analysis_note2)]
1685-
pub(crate) struct CmseCallOutputStackSpill {
1686+
pub(crate) struct CmseOutputStackSpill {
16861687
#[primary_span]
16871688
#[label]
16881689
pub span: Span,
1690+
pub abi_name: &'static str,
16891691
}
16901692

16911693
#[derive(Diagnostic)]
@@ -1701,3 +1703,10 @@ pub(crate) struct BadReturnTypeNotation {
17011703
#[primary_span]
17021704
pub span: Span,
17031705
}
1706+
1707+
#[derive(Diagnostic)]
1708+
#[diag(hir_analysis_cmse_entry_generic, code = E0798)]
1709+
pub(crate) struct CmseEntryGeneric {
1710+
#[primary_span]
1711+
pub span: Span,
1712+
}

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(crate) 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

@@ -141,22 +182,22 @@ fn is_valid_cmse_output<'tcx>(
141182
Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
142183
}
143184

144-
fn cmse_layout_err<'tcx>(
145-
layout_err: &'tcx LayoutError<'tcx>,
146-
span: Span,
147-
) -> Option<crate::errors::CmseCallGeneric> {
185+
fn should_emit_generic_error<'tcx>(abi: abi::Abi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
148186
use LayoutError::*;
149187

150188
match layout_err {
151189
Unknown(ty) => {
152-
if ty.is_impl_trait() {
153-
None // prevent double reporting of this error
154-
} else {
155-
Some(errors::CmseCallGeneric { span })
190+
match abi {
191+
abi::Abi::CCmseNonSecureCall => {
192+
// prevent double reporting of this error
193+
!ty.is_impl_trait()
194+
}
195+
abi::Abi::CCmseNonSecureEntry => true,
196+
_ => bug!("invalid ABI: {abi}"),
156197
}
157198
}
158199
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
159-
None // not our job to report these
200+
false // not our job to report these
160201
}
161202
}
162203
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
2+
//@ needs-llvm-components: arm
3+
#![feature(cmse_nonsecure_entry, c_variadic, 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+
}
45+
46+
extern "C-cmse-nonsecure-entry" fn reference(x: &usize) -> usize {
47+
*x
48+
}
49+
50+
trait Trait {}
51+
52+
extern "C-cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait {
53+
//~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798]
54+
x
55+
}
56+
57+
extern "C-cmse-nonsecure-entry" fn static_trait_object(
58+
x: &'static dyn Trait,
59+
) -> &'static dyn Trait {
60+
//~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798]
61+
x
62+
}
63+
64+
#[repr(transparent)]
65+
struct WrapperTransparent<'a>(&'a dyn Trait);
66+
67+
extern "C-cmse-nonsecure-entry" fn wrapped_trait_object(
68+
x: WrapperTransparent,
69+
) -> WrapperTransparent {
70+
//~^ ERROR return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers [E0798]
71+
x
72+
}
73+
74+
extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
75+
//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg
76+
//~| ERROR requires `va_list` lang_item
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg
2+
--> $DIR/generics.rs:74:55
3+
|
4+
LL | extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
5+
| ^^^^^^
6+
7+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
8+
--> $DIR/generics.rs:31:1
9+
|
10+
LL | / extern "C-cmse-nonsecure-entry" fn introduced_generic<U: Copy>(
11+
LL | |
12+
LL | | _: U,
13+
LL | | _: u32,
14+
LL | | _: u32,
15+
LL | | _: u32,
16+
LL | | ) -> u64 {
17+
| |________^
18+
19+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
20+
--> $DIR/generics.rs:41:1
21+
|
22+
LL | extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: 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:15:5
27+
|
28+
LL | extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 {
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
32+
--> $DIR/generics.rs:20:5
33+
|
34+
LL | / extern "C-cmse-nonsecure-entry" fn ambient_generic_nested(
35+
LL | |
36+
LL | | _: Wrapper<T>,
37+
LL | | _: u32,
38+
LL | | _: u32,
39+
LL | | _: u32,
40+
LL | | ) -> u64 {
41+
| |____________^
42+
43+
error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers
44+
--> $DIR/generics.rs:52:67
45+
|
46+
LL | extern "C-cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait {
47+
| ^^^^^^^^^^ this type doesn't fit in the available registers
48+
|
49+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers
50+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
51+
52+
error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers
53+
--> $DIR/generics.rs:59:6
54+
|
55+
LL | ) -> &'static dyn Trait {
56+
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
57+
|
58+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers
59+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
60+
61+
error[E0798]: return value of `"C-cmse-nonsecure-entry"` function too large to pass via registers
62+
--> $DIR/generics.rs:69:6
63+
|
64+
LL | ) -> WrapperTransparent {
65+
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
66+
|
67+
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass their result via the available return registers
68+
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
69+
70+
error: requires `va_list` lang_item
71+
--> $DIR/generics.rs:74:55
72+
|
73+
LL | extern "C-cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
74+
| ^^^^^^
75+
76+
error: aborting due to 9 previous errors
77+
78+
For more information about this error, try `rustc --explain E0798`.

0 commit comments

Comments
 (0)