cmse: more accurate spans for excess parameters
Use the span of the types that don't fit, rather than the span of the whole signature.
This commit is contained in:
@@ -1616,7 +1616,7 @@ pub(crate) struct InvalidGenericReceiverTy<'tcx> {
|
||||
pub(crate) struct CmseInputsStackSpill {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub spans: Vec<Span>,
|
||||
pub plural: bool,
|
||||
pub abi: ExternAbi,
|
||||
}
|
||||
|
||||
@@ -44,20 +44,8 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||
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 = if let Some(ident) = fn_ptr_ty.param_idents[index] {
|
||||
ident.span.to(fn_ptr_ty.decl.inputs[index].span)
|
||||
} else {
|
||||
fn_ptr_ty.decl.inputs[index].span
|
||||
}
|
||||
.to(fn_ptr_ty.decl.inputs.last().unwrap().span);
|
||||
let plural = fn_ptr_ty.param_idents.len() - index != 1;
|
||||
dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi });
|
||||
}
|
||||
match is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) {
|
||||
Ok(()) => {}
|
||||
Err(layout_err) => {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
|
||||
@@ -65,18 +53,11 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
match is_valid_cmse_output(tcx, fn_sig) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
let span = fn_ptr_ty.decl.output.span();
|
||||
dcx.emit_err(errors::CmseOutputStackSpill { span, abi });
|
||||
if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
|
||||
}
|
||||
Err(layout_err) => {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
ExternAbi::CmseNonSecureEntry => {
|
||||
let hir_node = tcx.hir_node(hir_id);
|
||||
@@ -91,15 +72,8 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||
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 });
|
||||
}
|
||||
match is_valid_cmse_inputs(tcx, dcx, fn_sig, decl, abi) {
|
||||
Ok(()) => {}
|
||||
Err(layout_err) => {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
|
||||
@@ -107,18 +81,11 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
match is_valid_cmse_output(tcx, fn_sig) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
let span = decl.output.span();
|
||||
dcx.emit_err(errors::CmseOutputStackSpill { span, abi });
|
||||
if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, decl, abi) {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
|
||||
}
|
||||
Err(layout_err) => {
|
||||
if should_emit_generic_error(abi, layout_err) {
|
||||
dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span });
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -127,16 +94,19 @@ pub(crate) fn validate_cmse_abi<'tcx>(
|
||||
/// Returns whether the inputs will fit into the available registers
|
||||
fn is_valid_cmse_inputs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
|
||||
let mut span = None;
|
||||
fn_decl: &hir::FnDecl<'tcx>,
|
||||
abi: ExternAbi,
|
||||
) -> Result<(), &'tcx LayoutError<'tcx>> {
|
||||
let mut accum = 0u64;
|
||||
let mut excess_argument_spans = Vec::new();
|
||||
|
||||
// this type is only used for layout computation, which does not rely on regions
|
||||
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
||||
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
|
||||
|
||||
for (index, ty) in fn_sig.inputs().iter().enumerate() {
|
||||
for (ty, hir_ty) in fn_sig.inputs().iter().zip(fn_decl.inputs) {
|
||||
let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?;
|
||||
|
||||
let align = layout.layout.align().bytes();
|
||||
@@ -147,21 +117,28 @@ fn is_valid_cmse_inputs<'tcx>(
|
||||
|
||||
// i.e. exceeds 4 32-bit registers
|
||||
if accum > 16 {
|
||||
span = span.or(Some(index));
|
||||
excess_argument_spans.push(hir_ty.span);
|
||||
}
|
||||
}
|
||||
|
||||
match span {
|
||||
None => Ok(Ok(())),
|
||||
Some(span) => Ok(Err(span)),
|
||||
if !excess_argument_spans.is_empty() {
|
||||
// fn f(x: u32, y: u32, z: u32, w: u16, q: u16) -> u32,
|
||||
// ^^^^^^
|
||||
let plural = excess_argument_spans.len() != 1;
|
||||
dcx.emit_err(errors::CmseInputsStackSpill { spans: excess_argument_spans, plural, abi });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether the output will fit into the available registers
|
||||
fn is_valid_cmse_output<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
fn_decl: &hir::FnDecl<'tcx>,
|
||||
abi: ExternAbi,
|
||||
) -> Result<(), &'tcx LayoutError<'tcx>> {
|
||||
// this type is only used for layout computation, which does not rely on regions
|
||||
let fn_sig = tcx.instantiate_bound_regions_with_erased(fn_sig);
|
||||
let fn_sig = tcx.erase_and_anonymize_regions(fn_sig);
|
||||
@@ -183,7 +160,11 @@ fn is_valid_cmse_output<'tcx>(
|
||||
let typing_env = ty::TypingEnv::fully_monomorphized();
|
||||
let layout = tcx.layout_of(typing_env.as_query_input(return_type))?;
|
||||
|
||||
Ok(is_valid_cmse_output_layout(layout))
|
||||
if !is_valid_cmse_output_layout(layout) {
|
||||
dcx.emit_err(errors::CmseOutputStackSpill { span: fn_decl.output.span(), abi });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether the output will fit into the available registers
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers
|
||||
--> $DIR/params-via-stack.rs:16:61
|
||||
--> $DIR/params-via-stack.rs:16:64
|
||||
|
|
||||
LL | f1: extern "cmse-nonsecure-call" fn(u32, u32, u32, u32, x: u32, y: u32),
|
||||
| ^^^^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||
| ^^^ ^^^ these arguments don't fit in the available registers
|
||||
| |
|
||||
| these arguments don't fit in the available registers
|
||||
|
|
||||
= note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass
|
||||
--> $DIR/params-via-stack.rs:15:76
|
||||
|
|
||||
LL | pub extern "cmse-nonsecure-entry" fn f1(_: u32, _: u32, _: u32, _: u32, _: u32, _: u32) {}
|
||||
| ^^^^^^^^^^^ these arguments don't fit in the available registers
|
||||
| ^^^ ^^^ these arguments don't fit in the available registers
|
||||
| |
|
||||
| these arguments don't fit in the available registers
|
||||
|
|
||||
= note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit available argument registers
|
||||
|
||||
|
||||
Reference in New Issue
Block a user