diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 81bdfc1705a1..6b8c2e4d0610 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -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 { diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs index 4565d89f0dc8..55160f7a0f00 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.rs @@ -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] ) { } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr index 4351444225b5..6b7446abc8eb 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/return-via-stack.stderr @@ -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`.