Skip to content

Commit 731e360

Browse files
authored
Rollup merge of #130747 - folkertdev:c-cmse-nonsecure-entry-error-messages, r=compiler-errors
improve error messages for `C-cmse-nonsecure-entry` functions fixes #81347 tracking issue: #75835 brings error messages and testing for `C-cmse-nonsecure-entry` in line with `C-cmse-nonsecure-call`. r? `@compiler-errors`
2 parents fb691b4 + 10aa255 commit 731e360

14 files changed

+612
-108
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
@@ -1627,23 +1627,25 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
16271627
pub(crate) struct EffectsWithoutNextSolver;
16281628

16291629
#[derive(Diagnostic)]
1630-
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
1630+
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
16311631
#[note]
1632-
pub(crate) struct CmseCallInputsStackSpill {
1632+
pub(crate) struct CmseInputsStackSpill {
16331633
#[primary_span]
16341634
#[label]
16351635
pub span: Span,
16361636
pub plural: bool,
1637+
pub abi_name: &'static str,
16371638
}
16381639

16391640
#[derive(Diagnostic)]
1640-
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
1641+
#[diag(hir_analysis_cmse_output_stack_spill, code = E0798)]
16411642
#[note(hir_analysis_note1)]
16421643
#[note(hir_analysis_note2)]
1643-
pub(crate) struct CmseCallOutputStackSpill {
1644+
pub(crate) struct CmseOutputStackSpill {
16441645
#[primary_span]
16451646
#[label]
16461647
pub span: Span,
1648+
pub abi_name: &'static str,
16471649
}
16481650

16491651
#[derive(Diagnostic)]
@@ -1659,3 +1661,10 @@ pub(crate) struct BadReturnTypeNotation {
16591661
#[primary_span]
16601662
pub span: Span,
16611663
}
1664+
1665+
#[derive(Diagnostic)]
1666+
#[diag(hir_analysis_cmse_entry_generic, code = E0798)]
1667+
pub(crate) struct CmseEntryGeneric {
1668+
#[primary_span]
1669+
pub span: Span,
1670+
}

compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs

+100-57
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err};
22
use rustc_hir::{self as hir, HirId};
3+
use rustc_middle::bug;
34
use rustc_middle::ty::layout::LayoutError;
45
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
5-
use rustc_span::Span;
66
use rustc_target::spec::abi;
77

88
use crate::errors;
@@ -17,61 +17,104 @@ pub(crate) fn validate_cmse_abi<'tcx>(
1717
abi: abi::Abi,
1818
fn_sig: ty::PolyFnSig<'tcx>,
1919
) {
20-
if let abi::Abi::CCmseNonSecureCall = abi {
21-
let hir_node = tcx.hir_node(hir_id);
22-
let hir::Node::Ty(hir::Ty {
23-
span: bare_fn_span,
24-
kind: hir::TyKind::BareFn(bare_fn_ty),
25-
..
26-
}) = hir_node
27-
else {
28-
let span = match tcx.parent_hir_node(hir_id) {
29-
hir::Node::Item(hir::Item {
30-
kind: hir::ItemKind::ForeignMod { .. }, span, ..
31-
}) => *span,
32-
_ => tcx.hir().span(hir_id),
20+
let abi_name = abi.name();
21+
22+
match abi {
23+
abi::Abi::CCmseNonSecureCall => {
24+
let hir_node = tcx.hir_node(hir_id);
25+
let hir::Node::Ty(hir::Ty {
26+
span: bare_fn_span,
27+
kind: hir::TyKind::BareFn(bare_fn_ty),
28+
..
29+
}) = hir_node
30+
else {
31+
let span = match tcx.parent_hir_node(hir_id) {
32+
hir::Node::Item(hir::Item {
33+
kind: hir::ItemKind::ForeignMod { .. },
34+
span,
35+
..
36+
}) => *span,
37+
_ => tcx.hir().span(hir_id),
38+
};
39+
struct_span_code_err!(
40+
tcx.dcx(),
41+
span,
42+
E0781,
43+
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
44+
)
45+
.emit();
46+
return;
3347
};
34-
struct_span_code_err!(
35-
tcx.dcx(),
36-
span,
37-
E0781,
38-
"the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
39-
)
40-
.emit();
41-
return;
42-
};
4348

44-
match is_valid_cmse_inputs(tcx, fn_sig) {
45-
Ok(Ok(())) => {}
46-
Ok(Err(index)) => {
47-
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
48-
// ^^^^^^
49-
let span = bare_fn_ty.param_names[index]
50-
.span
51-
.to(bare_fn_ty.decl.inputs[index].span)
52-
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
53-
let plural = bare_fn_ty.param_names.len() - index != 1;
54-
dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural });
55-
}
56-
Err(layout_err) => {
57-
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
58-
dcx.emit_err(err);
49+
match is_valid_cmse_inputs(tcx, fn_sig) {
50+
Ok(Ok(())) => {}
51+
Ok(Err(index)) => {
52+
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
53+
// ^^^^^^
54+
let span = bare_fn_ty.param_names[index]
55+
.span
56+
.to(bare_fn_ty.decl.inputs[index].span)
57+
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
58+
let plural = bare_fn_ty.param_names.len() - index != 1;
59+
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, 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+
}
5965
}
6066
}
67+
68+
match is_valid_cmse_output(tcx, fn_sig) {
69+
Ok(true) => {}
70+
Ok(false) => {
71+
let span = bare_fn_ty.decl.output.span();
72+
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
73+
}
74+
Err(layout_err) => {
75+
if should_emit_generic_error(abi, layout_err) {
76+
dcx.emit_err(errors::CmseCallGeneric { span: *bare_fn_span });
77+
}
78+
}
79+
};
6180
}
81+
abi::Abi::CCmseNonSecureEntry => {
82+
let hir_node = tcx.hir_node(hir_id);
83+
let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else {
84+
// might happen when this ABI is used incorrectly. That will be handled elsewhere
85+
return;
86+
};
6287

63-
match is_valid_cmse_output(tcx, fn_sig) {
64-
Ok(true) => {}
65-
Ok(false) => {
66-
let span = bare_fn_ty.decl.output.span();
67-
dcx.emit_err(errors::CmseCallOutputStackSpill { span });
68-
}
69-
Err(layout_err) => {
70-
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
71-
dcx.emit_err(err);
88+
match is_valid_cmse_inputs(tcx, fn_sig) {
89+
Ok(Ok(())) => {}
90+
Ok(Err(index)) => {
91+
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
92+
// ^^^^^^
93+
let span = decl.inputs[index].span.to(decl.inputs.last().unwrap().span);
94+
let plural = decl.inputs.len() - index != 1;
95+
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, 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+
}
72101
}
73102
}
74-
};
103+
104+
match is_valid_cmse_output(tcx, fn_sig) {
105+
Ok(true) => {}
106+
Ok(false) => {
107+
let span = decl.output.span();
108+
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
109+
}
110+
Err(layout_err) => {
111+
if should_emit_generic_error(abi, layout_err) {
112+
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
113+
}
114+
}
115+
};
116+
}
117+
_ => (),
75118
}
76119
}
77120

@@ -152,22 +195,22 @@ fn is_valid_cmse_output<'tcx>(
152195
Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
153196
}
154197

155-
fn cmse_layout_err<'tcx>(
156-
layout_err: &'tcx LayoutError<'tcx>,
157-
span: Span,
158-
) -> Option<crate::errors::CmseCallGeneric> {
198+
fn should_emit_generic_error<'tcx>(abi: abi::Abi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
159199
use LayoutError::*;
160200

161201
match layout_err {
162202
Unknown(ty) => {
163-
if ty.is_impl_trait() {
164-
None // prevent double reporting of this error
165-
} else {
166-
Some(errors::CmseCallGeneric { span })
203+
match abi {
204+
abi::Abi::CCmseNonSecureCall => {
205+
// prevent double reporting of this error
206+
!ty.is_impl_trait()
207+
}
208+
abi::Abi::CCmseNonSecureEntry => true,
209+
_ => bug!("invalid ABI: {abi}"),
167210
}
168211
}
169212
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
170-
None // not our job to report these
213+
false // not our job to report these
171214
}
172215
}
173216
}
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+
}

0 commit comments

Comments
 (0)