Skip to content

Commit

Permalink
add error messages for C-cmse-nonsecure-entry
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Jul 22, 2024
1 parent b3a6cd6 commit 87224ba
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 69 deletions.
15 changes: 9 additions & 6 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,21 @@ hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are fo
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
hir_analysis_cmse_entry_generic =
functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
hir_analysis_cmse_inputs_stack_spill =
arguments for `"{$abi_name}"` function too large to pass via registers
.label = {$plural ->
[false] this argument doesn't
*[true] 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
.note = functions with the `"{$abi_name}"` 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
hir_analysis_cmse_output_stack_spill =
return value of `"{$abi_name}"` function too large to pass via registers
.label = this type doesn't fit in the available registers
.note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
.note1 = functions with the `"{$abi_name}"` ABI must pass their result via the available return registers
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
Expand Down
17 changes: 13 additions & 4 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1697,23 +1697,25 @@ pub struct InvalidReceiverTy<'tcx> {
pub struct EffectsWithoutNextSolver;

#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
#[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
#[note]
pub struct CmseCallInputsStackSpill {
pub struct CmseInputsStackSpill {
#[primary_span]
#[label]
pub span: Span,
pub plural: bool,
pub abi_name: &'static str,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
#[diag(hir_analysis_cmse_output_stack_spill, code = E0798)]
#[note(hir_analysis_note1)]
#[note(hir_analysis_note2)]
pub struct CmseCallOutputStackSpill {
pub struct CmseOutputStackSpill {
#[primary_span]
#[label]
pub span: Span,
pub abi_name: &'static str,
}

#[derive(Diagnostic)]
Expand All @@ -1722,3 +1724,10 @@ pub struct CmseCallGeneric {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_cmse_entry_generic, code = E0798)]
pub struct CmseEntryGeneric {
#[primary_span]
pub span: Span,
}
137 changes: 89 additions & 48 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_errors::DiagCtxtHandle;
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_middle::bug;
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;
Expand All @@ -18,49 +18,90 @@ pub fn validate_cmse_abi<'tcx>(
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;
};

match is_valid_cmse_inputs(tcx, fn_sig) {
Ok(Ok(())) => {}
Ok(Err(index)) => {
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
// ^^^^^^
let span = bare_fn_ty.param_names[index]
.span
.to(bare_fn_ty.decl.inputs[index].span)
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
let plural = bare_fn_ty.param_names.len() - index != 1;
dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural });
}
Err(layout_err) => {
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
dcx.emit_err(err);
let abi_name = abi.name();

match abi {
abi::Abi::CCmseNonSecureCall => {
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;
};

match is_valid_cmse_inputs(tcx, fn_sig) {
Ok(Ok(())) => {}
Ok(Err(index)) => {
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
// ^^^^^^
let span = bare_fn_ty.param_names[index]
.span
.to(bare_fn_ty.decl.inputs[index].span)
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
let plural = bare_fn_ty.param_names.len() - index != 1;
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name });
}
Err(layout_err) => {
if should_emit_generic_error(abi, layout_err) {
dcx.emit_err(errors::CmseCallGeneric { span: *bare_fn_span });
}
}
}
}

match is_valid_cmse_output(tcx, fn_sig) {
Ok(true) => {}
Ok(false) => {
let span = bare_fn_ty.decl.output.span();
dcx.emit_err(errors::CmseCallOutputStackSpill { span });
}
Err(layout_err) => {
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
dcx.emit_err(err);
match is_valid_cmse_output(tcx, fn_sig) {
Ok(true) => {}
Ok(false) => {
let span = bare_fn_ty.decl.output.span();
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
}
Err(layout_err) => {
if should_emit_generic_error(abi, layout_err) {
dcx.emit_err(errors::CmseCallGeneric { span: *bare_fn_span });
}
}
};
}
abi::Abi::CCmseNonSecureEntry => {
let hir_node = tcx.hir_node(hir_id);
let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else {
// might happen when this ABI is used incorrectly. That will be handled elsewhere
return;
};

match is_valid_cmse_inputs(tcx, fn_sig) {
Ok(Ok(())) => {}
Ok(Err(index)) => {
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
// ^^^^^^
let span = decl.inputs[index].span.to(decl.inputs.last().unwrap().span);
let plural = decl.inputs.len() - index != 1;
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi_name });
}
Err(layout_err) => {
if should_emit_generic_error(abi, layout_err) {
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
}
}
}
};

match is_valid_cmse_output(tcx, fn_sig) {
Ok(true) => {}
Ok(false) => {
let span = decl.output.span();
dcx.emit_err(errors::CmseOutputStackSpill { span, abi_name });
}
Err(layout_err) => {
if should_emit_generic_error(abi, layout_err) {
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
}
}
};
}
_ => (),
}
}

Expand Down Expand Up @@ -135,22 +176,22 @@ fn is_valid_cmse_output<'tcx>(
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> {
fn should_emit_generic_error<'tcx>(abi: abi::Abi, layout_err: &'tcx LayoutError<'tcx>) -> bool {
use LayoutError::*;

match layout_err {
Unknown(ty) => {
if ty.is_impl_trait() {
None // prevent double reporting of this error
} else {
Some(errors::CmseCallGeneric { span })
match abi {
abi::Abi::CCmseNonSecureCall => {
// prevent double reporting of this error
!ty.is_impl_trait()
}
abi::Abi::CCmseNonSecureEntry => true,
_ => bug!("invalid ABI: {abi}"),
}
}
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
None // not our job to report these
false // not our job to report these
}
}
}
44 changes: 44 additions & 0 deletions tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
//@ needs-llvm-components: arm
#![feature(cmse_nonsecure_entry, 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);

impl<T: Copy> Wrapper<T> {
extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 {
//~^ ERROR [E0798]
0
}

extern "C-cmse-nonsecure-entry" fn ambient_generic_nested(
//~^ ERROR [E0798]
_: Wrapper<T>,
_: u32,
_: u32,
_: u32,
) -> u64 {
0
}
}

extern "C-cmse-nonsecure-entry" fn introduced_generic<U: Copy>(
//~^ ERROR [E0798]
_: U,
_: u32,
_: u32,
_: u32,
) -> u64 {
0
}

extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 {
//~^ ERROR [E0798]
0
}
39 changes: 39 additions & 0 deletions tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
--> $DIR/generics.rs:31:1
|
LL | / extern "C-cmse-nonsecure-entry" fn introduced_generic<U: Copy>(
LL | |
LL | | _: U,
LL | | _: u32,
LL | | _: u32,
LL | | _: u32,
LL | | ) -> u64 {
| |________^

error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
--> $DIR/generics.rs:41:1
|
LL | extern "C-cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
--> $DIR/generics.rs:15:5
|
LL | extern "C-cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0798]: functions with the `"C-cmse-nonsecure-entry"` ABI cannot contain generics in their type
--> $DIR/generics.rs:20:5
|
LL | / extern "C-cmse-nonsecure-entry" fn ambient_generic_nested(
LL | |
LL | | _: Wrapper<T>,
LL | | _: u32,
LL | | _: u32,
LL | | _: u32,
LL | | ) -> u64 {
| |____________^

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0798`.
11 changes: 5 additions & 6 deletions tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//@ build-fail
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
//@ needs-llvm-components: arm
#![feature(cmse_nonsecure_entry, no_core, lang_items)]
Expand All @@ -14,14 +13,14 @@ impl Copy for u32 {}
pub struct AlignRelevant(u32);

#[no_mangle]
pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {}
pub extern "C-cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {} //~ ERROR [E0798]
#[no_mangle]
pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {}
pub extern "C-cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} //~ ERROR [E0798]
#[no_mangle]
pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {}
pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} //~ ERROR [E0798]
#[no_mangle]
pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {}
pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} //~ ERROR [E0798]

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

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

error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
--> $DIR/params-via-stack.rs:20:62
|
LL | pub extern "C-cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {}
| ^^^ this argument doesn't fit in the available registers
|
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers

error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
--> $DIR/params-via-stack.rs:22:64
|
LL | pub extern "C-cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {}
| ^^^ this argument doesn't fit in the available registers
|
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers

error[E0798]: arguments for `"C-cmse-nonsecure-entry"` function too large to pass via registers
--> $DIR/params-via-stack.rs:26:46
|
LL | pub extern "C-cmse-nonsecure-entry" fn f5(_: [u32; 5]) {}
| ^^^^^^^^ this argument doesn't fit in the available registers
|
= note: functions with the `"C-cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0798`.
Loading

0 comments on commit 87224ba

Please sign in to comment.