cmse: don't use BackendRepr when checking return type

This commit is contained in:
Folkert de Vries 2026-01-24 13:57:49 +01:00
parent 66daca1a85
commit 43ee28aa16
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
3 changed files with 60 additions and 39 deletions

View file

@ -1,8 +1,8 @@
use rustc_abi::{BackendRepr, ExternAbi, Float, Integer, Primitive, Scalar};
use rustc_abi::ExternAbi;
use rustc_errors::{DiagCtxtHandle, E0781, struct_span_code_err};
use rustc_hir::{self as hir, HirId};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
use rustc_middle::ty::layout::{LayoutCx, LayoutError, TyAndLayout};
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
@ -150,8 +150,9 @@ 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))?;
let layout_cx = LayoutCx::new(tcx, typing_env);
if !is_valid_cmse_output_layout(layout) {
if !is_valid_cmse_output_layout(layout_cx, layout) {
dcx.emit_err(errors::CmseOutputStackSpill { span: fn_decl.output.span(), abi });
}
@ -159,25 +160,32 @@ fn is_valid_cmse_output<'tcx>(
}
/// Returns whether the output will fit into the available registers
fn is_valid_cmse_output_layout<'tcx>(layout: TyAndLayout<'tcx>) -> bool {
fn is_valid_cmse_output_layout<'tcx>(cx: LayoutCx<'tcx>, mut layout: TyAndLayout<'tcx>) -> bool {
let size = layout.layout.size().bytes();
if size <= 4 {
return true;
} else if size > 8 {
} else if size != 8 {
return false;
}
// Accept scalar 64-bit types.
let BackendRepr::Scalar(scalar) = layout.layout.backend_repr else {
return false;
};
// Find the wrapped inner type of a transparent wrapper.
loop {
match layout.ty.kind() {
ty::Adt(adt_def, _) if adt_def.repr().transparent() => {
// Find the non-1-ZST field, and recurse.
(_, layout) = layout.non_1zst_field(&cx).unwrap();
}
// Not a transparent type, no further unfolding.
_ => break,
}
}
let Scalar::Initialized { value, .. } = scalar else {
return false;
};
matches!(value, Primitive::Int(Integer::I64, _) | Primitive::Float(Float::F64))
// Accept (transparently wrapped) scalar 64-bit primitives.
matches!(
layout.ty.kind(),
ty::Int(ty::IntTy::I64) | ty::Uint(ty::UintTy::U64) | ty::Float(ty::FloatTy::F64)
)
}
fn should_emit_layout_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool {

View file

@ -13,6 +13,9 @@ use minicore::*;
#[repr(C)]
pub struct ReprCU64(u64);
#[repr(Rust)]
pub struct ReprRustU64(u64);
#[repr(C)]
pub struct ReprCBytes(u8, u8, u8, u8, u8);
@ -25,10 +28,11 @@ pub struct ReprCAlign16(u16);
#[no_mangle]
pub fn test(
f1: extern "cmse-nonsecure-call" fn() -> ReprCU64, //~ ERROR [E0798]
f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798]
f3: extern "cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798]
f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798]
f5: extern "cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798]
f2: extern "cmse-nonsecure-call" fn() -> ReprRustU64, //~ ERROR [E0798]
f3: extern "cmse-nonsecure-call" fn() -> ReprCBytes, //~ ERROR [E0798]
f4: extern "cmse-nonsecure-call" fn() -> U64Compound, //~ ERROR [E0798]
f5: extern "cmse-nonsecure-call" fn() -> ReprCAlign16, //~ ERROR [E0798]
f6: extern "cmse-nonsecure-call" fn() -> [u8; 5], //~ ERROR [E0798]
) {
}

View file

@ -1,5 +1,5 @@
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:37:48
--> $DIR/return-via-stack.rs:41:48
|
LL | u128: extern "cmse-nonsecure-call" fn() -> u128,
| ^^^^ this type doesn't fit in the available registers
@ -8,7 +8,7 @@ LL | u128: extern "cmse-nonsecure-call" fn() -> u128,
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:38:48
--> $DIR/return-via-stack.rs:42:48
|
LL | i128: extern "cmse-nonsecure-call" fn() -> i128,
| ^^^^ this type doesn't fit in the available registers
@ -17,7 +17,7 @@ LL | i128: extern "cmse-nonsecure-call" fn() -> i128,
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:27:46
--> $DIR/return-via-stack.rs:30:46
|
LL | f1: extern "cmse-nonsecure-call" fn() -> ReprCU64,
| ^^^^^^^^ this type doesn't fit in the available registers
@ -26,43 +26,52 @@ LL | f1: extern "cmse-nonsecure-call" fn() -> ReprCU64,
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:28:46
--> $DIR/return-via-stack.rs:31:46
|
LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCBytes,
| ^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:29:46
|
LL | f3: extern "cmse-nonsecure-call" fn() -> U64Compound,
LL | f2: extern "cmse-nonsecure-call" fn() -> ReprRustU64,
| ^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:30:46
--> $DIR/return-via-stack.rs:32:46
|
LL | f4: extern "cmse-nonsecure-call" fn() -> ReprCAlign16,
LL | f3: extern "cmse-nonsecure-call" fn() -> ReprCBytes,
| ^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:33:46
|
LL | f4: extern "cmse-nonsecure-call" fn() -> U64Compound,
| ^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:34:46
|
LL | f5: extern "cmse-nonsecure-call" fn() -> ReprCAlign16,
| ^^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:31:46
--> $DIR/return-via-stack.rs:35:46
|
LL | f5: extern "cmse-nonsecure-call" fn() -> [u8; 5],
LL | f6: extern "cmse-nonsecure-call" fn() -> [u8; 5],
| ^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:53:46
--> $DIR/return-via-stack.rs:57:46
|
LL | f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64,
| ^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
@ -71,7 +80,7 @@ LL | f1: extern "cmse-nonsecure-call" fn() -> ReprRustUnionU64,
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/return-via-stack.rs:54:46
--> $DIR/return-via-stack.rs:58:46
|
LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64,
| ^^^^^^^^^^^^^ this type doesn't fit in the available registers
@ -79,6 +88,6 @@ LL | f2: extern "cmse-nonsecure-call" fn() -> ReprCUnionU64,
= note: functions with the `"cmse-nonsecure-call"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error: aborting due to 9 previous errors
error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0798`.