From f62be66e9447bcf00064af4c8f42d789cc5e9782 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 01:07:26 +0200 Subject: [PATCH 1/6] cmse: additional `impl Trait` tests --- .../src/hir_ty_lowering/cmse.rs | 2 +- .../cmse-nonsecure-call/generics.rs | 7 ++- .../cmse-nonsecure-call/generics.stderr | 34 ++++++++---- .../cmse-nonsecure-entry/generics.rs | 28 +++++++--- .../cmse-nonsecure-entry/generics.stderr | 54 +++++++++++++------ 5 files changed, 88 insertions(+), 37 deletions(-) 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 91d1f89b74477..857d04593c277 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -216,7 +216,7 @@ fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError match abi { ExternAbi::CmseNonSecureCall => { // prevent double reporting of this error - !ty.is_impl_trait() + !ty.has_opaque_types() } ExternAbi::CmseNonSecureEntry => true, _ => bug!("invalid ABI: {abi}"), diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs index 2dc540675e2e6..72efd05814325 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs @@ -17,8 +17,11 @@ struct Test { f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl Copy, //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters //~| ERROR `impl Trait` is not allowed in `fn` pointer return types - f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] - f4: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, //~ ERROR [E0798] + f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32), + //~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters + //~| ERROR `impl Trait` is not allowed in `fn` pointer return types + f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798] + f5: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, //~ ERROR [E0798] } type WithReference = extern "cmse-nonsecure-call" fn(&usize); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index 750dbf8d5707c..d3ef87394be6c 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -38,20 +38,36 @@ LL | f2: extern "cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> impl C | = note: `impl Trait` is only allowed in arguments and return types of functions and methods +error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters + --> $DIR/generics.rs:20:42 + | +LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32), + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + +error[E0562]: `impl Trait` is not allowed in `fn` pointer return types + --> $DIR/generics.rs:20:78 + | +LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> (impl Copy, u32), + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type - --> $DIR/generics.rs:20:9 + --> $DIR/generics.rs:23:9 | -LL | f3: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, +LL | f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type - --> $DIR/generics.rs:21:9 + --> $DIR/generics.rs:24:9 | -LL | f4: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, +LL | f5: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers - --> $DIR/generics.rs:27:71 + --> $DIR/generics.rs:30:71 | LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait; | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -60,7 +76,7 @@ LL | type WithTraitObject = extern "cmse-nonsecure-call" fn(&dyn Trait) -> &dyn = 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/generics.rs:31:60 + --> $DIR/generics.rs:34:60 | LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait; | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -69,7 +85,7 @@ LL | extern "cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Tra = 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/generics.rs:38:60 + --> $DIR/generics.rs:41:60 | LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent; | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -78,12 +94,12 @@ LL | extern "cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTranspare = note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size error[E0045]: C-variadic functions with the "cmse-nonsecure-call" calling convention are not supported - --> $DIR/generics.rs:41:20 + --> $DIR/generics.rs:44:20 | LL | type WithVarArgs = extern "cmse-nonsecure-call" fn(u32, ...); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors Some errors have detailed explanations: E0045, E0412, E0562, E0798. For more information about an error, try `rustc --explain E0045`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 116f0fdc972fc..6f835538be9a3 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -37,11 +37,6 @@ extern "cmse-nonsecure-entry" fn introduced_generic( 0 } -extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { - //~^ ERROR [E0798] - 0 -} - extern "cmse-nonsecure-entry" fn reference(x: &usize) -> usize { *x } @@ -66,14 +61,31 @@ extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> x } -extern "cmse-nonsecure-entry" fn return_impl_trait(_: impl Copy) -> impl Copy { +extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { + //~^ ERROR [E0798] + 0 +} + +extern "cmse-nonsecure-entry" fn return_impl_trait() -> impl Copy { //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - //~| ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type 0u128 } -extern "cmse-nonsecure-entry" fn return_impl_trait_nested(v: (impl Copy, i32)) -> (impl Copy, i32) { +extern "cmse-nonsecure-entry" fn return_impl_trait_nested() -> (impl Copy, i32) { + //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + (0u128, 0i32) +} + +extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { + //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + //~| ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + v +} + +extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type //~| ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + v: (impl Copy, i32), +) -> (impl Copy, i32) { v } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index 4158fef4553a4..2c46cd708960f 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -11,36 +11,44 @@ LL | | ) -> u64 { | |________^ error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:40:1 + --> $DIR/generics.rs:64:1 | LL | extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:69:1 + --> $DIR/generics.rs:79:1 | -LL | extern "cmse-nonsecure-entry" fn return_impl_trait(_: impl Copy) -> impl Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:69:1 + --> $DIR/generics.rs:79:1 | -LL | extern "cmse-nonsecure-entry" fn return_impl_trait(_: impl Copy) -> impl Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:75:1 + --> $DIR/generics.rs:85:1 | -LL | extern "cmse-nonsecure-entry" fn return_impl_trait_nested(v: (impl Copy, i32)) -> (impl Copy, i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( +LL | | +LL | | +LL | | v: (impl Copy, i32), +LL | | ) -> (impl Copy, i32) { + | |_____________________^ error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:75:1 + --> $DIR/generics.rs:85:1 | -LL | extern "cmse-nonsecure-entry" fn return_impl_trait_nested(v: (impl Copy, i32)) -> (impl Copy, i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( +LL | | +LL | | +LL | | v: (impl Copy, i32), +LL | | ) -> (impl Copy, i32) { + | |_____________________^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` @@ -63,7 +71,7 @@ LL | | ) -> u64 { | |____________^ error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers - --> $DIR/generics.rs:51:65 + --> $DIR/generics.rs:46:65 | LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait { | ^^^^^^^^^^ this type doesn't fit in the available registers @@ -72,7 +80,7 @@ LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait = 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-entry"` function too large to pass via registers - --> $DIR/generics.rs:56:80 + --> $DIR/generics.rs:51:80 | LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -81,7 +89,7 @@ LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) = 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-entry"` function too large to pass via registers - --> $DIR/generics.rs:64:81 + --> $DIR/generics.rs:59:81 | LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent { | ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers @@ -89,6 +97,18 @@ LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent = note: functions with the `"cmse-nonsecure-entry"` 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 11 previous errors +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + --> $DIR/generics.rs:69:1 + | +LL | extern "cmse-nonsecure-entry" fn return_impl_trait() -> impl Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + --> $DIR/generics.rs:74:1 + | +LL | extern "cmse-nonsecure-entry" fn return_impl_trait_nested() -> (impl Copy, i32) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0798`. From f4d8bd3b47d9b9fd695b894927b04b2bb711a475 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 13:40:42 +0200 Subject: [PATCH 2/6] 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. --- compiler/rustc_hir_analysis/src/errors.rs | 2 +- .../src/hir_ty_lowering/cmse.rs | 89 ++++++++----------- .../params-via-stack.stderr | 6 +- .../params-via-stack.stderr | 4 +- 4 files changed, 43 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 3b6367219b7ff..db69653a27e9b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1616,7 +1616,7 @@ pub(crate) struct InvalidGenericReceiverTy<'tcx> { pub(crate) struct CmseInputsStackSpill { #[primary_span] #[label] - pub span: Span, + pub spans: Vec, pub plural: bool, pub abi: ExternAbi, } 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 857d04593c277..7e2938d1447ca 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -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 }); - } - Err(layout_err) => { - if should_emit_generic_error(abi, layout_err) { - dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span }); - } + 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 }); } - }; + } } 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 }); - } - Err(layout_err) => { - if should_emit_generic_error(abi, layout_err) { - dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span }); - } + 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 }); } - }; + } } _ => (), } @@ -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, &'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> { + 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 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr index 5d59405fbd1b2..313f2bb8a6ae4 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -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 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr index f8b96bddc9479..221fc7cf86475 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr @@ -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 From b47de64cdbfade1e8f3b4c21d338875a2c2ace7d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 13:42:49 +0200 Subject: [PATCH 3/6] cmse: rephrase error message when types don't fit --- compiler/rustc_hir_analysis/messages.ftl | 7 ++---- compiler/rustc_hir_analysis/src/errors.rs | 1 - .../src/hir_ty_lowering/cmse.rs | 3 +-- .../params-via-stack.stderr | 22 +++++++++---------- .../params-via-stack.stderr | 22 +++++++++---------- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 06f2ec512ab1f..3ffced25489c5 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -80,11 +80,8 @@ hir_analysis_cmse_entry_generic = hir_analysis_cmse_inputs_stack_spill = arguments for `{$abi}` 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 `{$abi}` ABI must pass all their arguments via the 4 32-bit available argument registers + .label = does not fit in the available registers + .note = functions with the `{$abi}` ABI must pass all their arguments via the 4 32-bit argument registers hir_analysis_cmse_output_stack_spill = return value of `{$abi}` function too large to pass via registers diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index db69653a27e9b..b57783ff6222b 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1617,7 +1617,6 @@ pub(crate) struct CmseInputsStackSpill { #[primary_span] #[label] pub spans: Vec, - pub plural: bool, pub abi: ExternAbi, } 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 7e2938d1447ca..a648653744411 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -124,8 +124,7 @@ fn is_valid_cmse_inputs<'tcx>( 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 }); + dcx.emit_err(errors::CmseInputsStackSpill { spans: excess_argument_spans, abi }); } Ok(()) diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr index 313f2bb8a6ae4..5a059e4df7b10 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/params-via-stack.stderr @@ -2,43 +2,43 @@ error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass v --> $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 + | ^^^ ^^^ does not fit in the available registers | | - | these arguments don't fit in the available registers + | does not 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 + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers --> $DIR/params-via-stack.rs:17:61 | LL | f2: extern "cmse-nonsecure-call" fn(u32, u32, u32, u16, u16), - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers --> $DIR/params-via-stack.rs:18:51 | LL | f3: extern "cmse-nonsecure-call" fn(u32, u64, u32), - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers --> $DIR/params-via-stack.rs:19:56 | LL | f4: extern "cmse-nonsecure-call" fn(AlignRelevant, u32), - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-call"` function too large to pass via registers --> $DIR/params-via-stack.rs:20:41 | LL | f5: extern "cmse-nonsecure-call" fn([u32; 5]), - | ^^^^^^^^ this argument doesn't fit in the available registers + | ^^^^^^^^ does not 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 + = note: functions with the `"cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit argument registers error: aborting due to 5 previous errors diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr index 221fc7cf86475..3d523fc7be679 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-via-stack.stderr @@ -2,43 +2,43 @@ 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 + | ^^^ ^^^ does not fit in the available registers | | - | these arguments don't fit in the available registers + | does not 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 + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/params-via-stack.rs:17:76 | LL | pub extern "cmse-nonsecure-entry" fn f2(_: u32, _: u32, _: u32, _: u16, _: u16) {} - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/params-via-stack.rs:19:60 | LL | pub extern "cmse-nonsecure-entry" fn f3(_: u32, _: u64, _: u32) {} - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/params-via-stack.rs:21:62 | LL | pub extern "cmse-nonsecure-entry" fn f4(_: AlignRelevant, _: u32) {} - | ^^^ this argument doesn't fit in the available registers + | ^^^ does not 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 + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error[E0798]: arguments for `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/params-via-stack.rs:25:44 | LL | pub extern "cmse-nonsecure-entry" fn f5(_: [u32; 5]) {} - | ^^^^^^^^ this argument doesn't fit in the available registers + | ^^^^^^^^ does not 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 + = note: functions with the `"cmse-nonsecure-entry"` ABI must pass all their arguments via the 4 32-bit argument registers error: aborting due to 5 previous errors From 98d3864310711946f1374c8bac5723edf626efb8 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 14:05:47 +0200 Subject: [PATCH 4/6] cmse: rephrase error message when signature uses generics --- compiler/rustc_hir_analysis/messages.ftl | 8 ++-- compiler/rustc_hir_analysis/src/errors.rs | 14 +++--- .../src/hir_ty_lowering/cmse.rs | 13 ++--- .../cmse-nonsecure-call/generics.stderr | 4 +- .../cmse-nonsecure-entry/generics.rs | 12 ++--- .../cmse-nonsecure-entry/generics.stderr | 47 ++++++++----------- 6 files changed, 46 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 3ffced25489c5..6add9baa1520f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -72,11 +72,11 @@ hir_analysis_cannot_capture_late_bound_ty = hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present .label = `for<...>` is here -hir_analysis_cmse_call_generic = - function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type +hir_analysis_cmse_generic = + generics are not allowed in `extern {$abi}` signatures -hir_analysis_cmse_entry_generic = - functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +hir_analysis_cmse_impl_trait = + `impl Trait` is not allowed in `extern {$abi}` signatures hir_analysis_cmse_inputs_stack_spill = arguments for `{$abi}` function too large to pass via registers diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index b57783ff6222b..49c5106422881 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1632,22 +1632,24 @@ pub(crate) struct CmseOutputStackSpill { } #[derive(Diagnostic)] -#[diag(hir_analysis_cmse_call_generic, code = E0798)] -pub(crate) struct CmseCallGeneric { +#[diag(hir_analysis_cmse_generic, code = E0798)] +pub(crate) struct CmseGeneric { #[primary_span] pub span: Span, + pub abi: ExternAbi, } #[derive(Diagnostic)] -#[diag(hir_analysis_bad_return_type_notation_position)] -pub(crate) struct BadReturnTypeNotation { +#[diag(hir_analysis_cmse_impl_trait, code = E0798)] +pub(crate) struct CmseImplTrait { #[primary_span] pub span: Span, + pub abi: ExternAbi, } #[derive(Diagnostic)] -#[diag(hir_analysis_cmse_entry_generic, code = E0798)] -pub(crate) struct CmseEntryGeneric { +#[diag(hir_analysis_bad_return_type_notation_position)] +pub(crate) struct BadReturnTypeNotation { #[primary_span] pub span: Span, } 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 a648653744411..9a31119c7f5a7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -48,14 +48,14 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(()) => {} Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { - dcx.emit_err(errors::CmseCallGeneric { span: *fn_ptr_span }); + dcx.emit_err(errors::CmseGeneric { span: *fn_ptr_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 }); + dcx.emit_err(errors::CmseGeneric { span: *fn_ptr_span, abi }); } } } @@ -76,14 +76,14 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(()) => {} Err(layout_err) => { if should_emit_generic_error(abi, layout_err) { - dcx.emit_err(errors::CmseEntryGeneric { span: *fn_sig_span }); + dcx.emit_err(errors::CmseGeneric { span: *fn_sig_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 }); + dcx.emit_err(errors::CmseGeneric { span: *fn_sig_span, abi }); } } } @@ -152,8 +152,9 @@ fn is_valid_cmse_output<'tcx>( // `#[no_mangle]` or similar, so generics in the type really don't make sense. // // see also https://github.com/rust-lang/rust/issues/147242. - if return_type.has_opaque_types() { - return Err(tcx.arena.alloc(LayoutError::TooGeneric(return_type))); + if abi == ExternAbi::CmseNonSecureEntry && return_type.has_opaque_types() { + dcx.emit_err(errors::CmseImplTrait { span: fn_decl.output.span(), abi }); + return Ok(()); } let typing_env = ty::TypingEnv::fully_monomorphized(); diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index d3ef87394be6c..d70369c46fbeb 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -54,13 +54,13 @@ LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures --> $DIR/generics.rs:23:9 | LL | f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: function pointers with the `"cmse-nonsecure-call"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures --> $DIR/generics.rs:24:9 | LL | f5: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 6f835538be9a3..2b4ddf5e31d33 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -67,25 +67,25 @@ extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32 } extern "cmse-nonsecure-entry" fn return_impl_trait() -> impl Copy { - //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + //~^ ERROR `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures 0u128 } extern "cmse-nonsecure-entry" fn return_impl_trait_nested() -> (impl Copy, i32) { - //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + //~^ ERROR `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures (0u128, 0i32) } extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { - //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - //~| ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + //~^ ERROR generics are not allowed in `extern "cmse-nonsecure-entry"` signatures + //~| ERROR `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures v } extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( - //~^ ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - //~| ERROR functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type + //~^ ERROR generics are not allowed in `extern "cmse-nonsecure-entry"` signatures v: (impl Copy, i32), ) -> (impl Copy, i32) { + //~^ ERROR `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures v } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index 2c46cd708960f..e61051a4a26f4 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,4 +1,4 @@ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:30:1 | LL | / extern "cmse-nonsecure-entry" fn introduced_generic( @@ -10,55 +10,46 @@ LL | | _: u32, LL | | ) -> u64 { | |________^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:64:1 | LL | extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:79:1 | LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:79:1 +error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures + --> $DIR/generics.rs:79:71 | LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + | ^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:85:1 | LL | / extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( LL | | -LL | | LL | | v: (impl Copy, i32), LL | | ) -> (impl Copy, i32) { | |_____________________^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:85:1 +error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures + --> $DIR/generics.rs:88:6 | -LL | / extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( -LL | | -LL | | -LL | | v: (impl Copy, i32), -LL | | ) -> (impl Copy, i32) { - | |_____________________^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | ) -> (impl Copy, i32) { + | ^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:14:5 | LL | extern "cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type +error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:19:5 | LL | / extern "cmse-nonsecure-entry" fn ambient_generic_nested( @@ -97,17 +88,17 @@ LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent = note: functions with the `"cmse-nonsecure-entry"` 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]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:69:1 +error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures + --> $DIR/generics.rs:69:57 | LL | extern "cmse-nonsecure-entry" fn return_impl_trait() -> impl Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ -error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type - --> $DIR/generics.rs:74:1 +error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures + --> $DIR/generics.rs:74:64 | LL | extern "cmse-nonsecure-entry" fn return_impl_trait_nested() -> (impl Copy, i32) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to 13 previous errors From 760ea07840f7eb78664355a52150a64964f57c47 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 14:10:13 +0200 Subject: [PATCH 5/6] cmse: more accurate span for generic arguments --- .../src/hir_ty_lowering/cmse.rs | 46 ++++++++--------- .../cmse-nonsecure-call/generics.stderr | 8 +-- .../cmse-nonsecure-entry/generics.rs | 6 +-- .../cmse-nonsecure-entry/generics.stderr | 49 +++++++------------ 4 files changed, 45 insertions(+), 64 deletions(-) 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 9a31119c7f5a7..b6c6e43b1d950 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -4,6 +4,7 @@ use rustc_hir::{self as hir, HirId}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; use crate::errors; @@ -20,11 +21,7 @@ pub(crate) fn validate_cmse_abi<'tcx>( match abi { ExternAbi::CmseNonSecureCall => { let hir_node = tcx.hir_node(hir_id); - let hir::Node::Ty(hir::Ty { - span: fn_ptr_span, - kind: hir::TyKind::FnPtr(fn_ptr_ty), - .. - }) = hir_node + let hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), .. }) = hir_node else { let span = match tcx.parent_hir_node(hir_id) { hir::Node::Item(hir::Item { @@ -44,24 +41,24 @@ pub(crate) fn validate_cmse_abi<'tcx>( return; }; - 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::CmseGeneric { span: *fn_ptr_span, abi }); - } + if let Err((span, layout_err)) = + is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) + { + if should_emit_layout_error(abi, layout_err) { + dcx.emit_err(errors::CmseGeneric { 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::CmseGeneric { span: *fn_ptr_span, abi }); + if should_emit_layout_error(abi, layout_err) { + let span = fn_ptr_ty.decl.output.span(); + dcx.emit_err(errors::CmseGeneric { span, abi }); } } } ExternAbi::CmseNonSecureEntry => { let hir_node = tcx.hir_node(hir_id); - let Some(hir::FnSig { decl, span: fn_sig_span, .. }) = hir_node.fn_sig() else { + let Some(hir::FnSig { decl, .. }) = hir_node.fn_sig() else { // might happen when this ABI is used incorrectly. That will be handled elsewhere return; }; @@ -72,18 +69,15 @@ pub(crate) fn validate_cmse_abi<'tcx>( return; } - 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::CmseGeneric { span: *fn_sig_span, abi }); - } + if let Err((span, layout_err)) = is_valid_cmse_inputs(tcx, dcx, fn_sig, decl, abi) { + if should_emit_layout_error(abi, layout_err) { + dcx.emit_err(errors::CmseGeneric { 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::CmseGeneric { span: *fn_sig_span, abi }); + if should_emit_layout_error(abi, layout_err) { + dcx.emit_err(errors::CmseGeneric { span: decl.output.span(), abi }); } } } @@ -98,7 +92,7 @@ fn is_valid_cmse_inputs<'tcx>( fn_sig: ty::PolyFnSig<'tcx>, fn_decl: &hir::FnDecl<'tcx>, abi: ExternAbi, -) -> Result<(), &'tcx LayoutError<'tcx>> { +) -> Result<(), (Span, &'tcx LayoutError<'tcx>)> { let mut accum = 0u64; let mut excess_argument_spans = Vec::new(); @@ -107,7 +101,9 @@ fn is_valid_cmse_inputs<'tcx>( let fn_sig = tcx.erase_and_anonymize_regions(fn_sig); 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 layout = tcx + .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty)) + .map_err(|e| (hir_ty.span, e))?; let align = layout.layout.align().bytes(); let size = layout.layout.size().bytes(); @@ -189,7 +185,7 @@ fn is_valid_cmse_output_layout<'tcx>(layout: TyAndLayout<'tcx>) -> bool { matches!(value, Primitive::Int(Integer::I64, _) | Primitive::Float(Float::F64)) } -fn should_emit_generic_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool { +fn should_emit_layout_error<'tcx>(abi: ExternAbi, layout_err: &'tcx LayoutError<'tcx>) -> bool { use LayoutError::*; match layout_err { diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr index d70369c46fbeb..75da78b0b75a9 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr @@ -55,16 +55,16 @@ LL | f3: extern "cmse-nonsecure-call" fn((impl Copy, u32), u32, u32, u32) -> = note: `impl Trait` is only allowed in arguments and return types of functions and methods error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures - --> $DIR/generics.rs:23:9 + --> $DIR/generics.rs:23:41 | LL | f4: extern "cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-call"` signatures - --> $DIR/generics.rs:24:9 + --> $DIR/generics.rs:24:41 | LL | f5: extern "cmse-nonsecure-call" fn(Wrapper, u32, u32, u32) -> u64, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error[E0798]: return value of `"cmse-nonsecure-call"` function too large to pass via registers --> $DIR/generics.rs:30:71 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 2b4ddf5e31d33..d01934929d97f 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -17,8 +17,8 @@ impl Wrapper { } extern "cmse-nonsecure-entry" fn ambient_generic_nested( - //~^ ERROR [E0798] _: Wrapper, + //~^ ERROR [E0798] _: u32, _: u32, _: u32, @@ -28,8 +28,8 @@ impl Wrapper { } extern "cmse-nonsecure-entry" fn introduced_generic( - //~^ ERROR [E0798] _: U, + //~^ ERROR [E0798] _: u32, _: u32, _: u32, @@ -83,8 +83,8 @@ extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy } extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( - //~^ ERROR generics are not allowed in `extern "cmse-nonsecure-entry"` signatures v: (impl Copy, i32), + //~^ ERROR generics are not allowed in `extern "cmse-nonsecure-entry"` signatures ) -> (impl Copy, i32) { //~^ ERROR `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures v diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index e61051a4a26f4..5ddd29883f867 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,26 +1,20 @@ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:30:1 - | -LL | / extern "cmse-nonsecure-entry" fn introduced_generic( -LL | | -LL | | _: U, -LL | | _: u32, -LL | | _: u32, -LL | | _: u32, -LL | | ) -> u64 { - | |________^ + --> $DIR/generics.rs:31:8 + | +LL | _: U, + | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:64:1 + --> $DIR/generics.rs:64:48 | LL | extern "cmse-nonsecure-entry" fn impl_trait(_: impl Copy, _: u32, _: u32, _: u32) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:79:1 + --> $DIR/generics.rs:79:57 | LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:79:71 @@ -29,13 +23,10 @@ LL | extern "cmse-nonsecure-entry" fn identity_impl_trait(v: impl Copy) -> impl | ^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:85:1 + --> $DIR/generics.rs:86:8 | -LL | / extern "cmse-nonsecure-entry" fn identity_impl_trait_nested( -LL | | -LL | | v: (impl Copy, i32), -LL | | ) -> (impl Copy, i32) { - | |_____________________^ +LL | v: (impl Copy, i32), + | ^^^^^^^^^^^^^^^^ error[E0798]: `impl Trait` is not allowed in `extern "cmse-nonsecure-entry"` signatures --> $DIR/generics.rs:88:6 @@ -44,22 +35,16 @@ LL | ) -> (impl Copy, i32) { | ^^^^^^^^^^^^^^^^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:14:5 + --> $DIR/generics.rs:14:57 | LL | extern "cmse-nonsecure-entry" fn ambient_generic(_: T, _: u32, _: u32, _: u32) -> u64 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error[E0798]: generics are not allowed in `extern "cmse-nonsecure-entry"` signatures - --> $DIR/generics.rs:19:5 - | -LL | / extern "cmse-nonsecure-entry" fn ambient_generic_nested( -LL | | -LL | | _: Wrapper, -LL | | _: u32, -LL | | _: u32, -LL | | _: u32, -LL | | ) -> u64 { - | |____________^ + --> $DIR/generics.rs:20:12 + | +LL | _: Wrapper, + | ^^^^^^^^^^ error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers --> $DIR/generics.rs:46:65 From bd5f908152b7b7dc2acf30bec6cd114e45ce4af3 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 8 Oct 2025 14:16:26 +0200 Subject: [PATCH 6/6] cmse: simplify input/output check control flow --- .../src/hir_ty_lowering/cmse.rs | 53 +++++++------------ 1 file changed, 19 insertions(+), 34 deletions(-) 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 b6c6e43b1d950..f8af6888923ce 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -18,11 +18,10 @@ pub(crate) fn validate_cmse_abi<'tcx>( abi: ExternAbi, fn_sig: ty::PolyFnSig<'tcx>, ) { - match abi { - ExternAbi::CmseNonSecureCall => { - let hir_node = tcx.hir_node(hir_id); - let hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), .. }) = hir_node - else { + let fn_decl = match abi { + ExternAbi::CmseNonSecureCall => match tcx.hir_node(hir_id) { + hir::Node::Ty(hir::Ty { kind: hir::TyKind::FnPtr(fn_ptr_ty), .. }) => fn_ptr_ty.decl, + _ => { let span = match tcx.parent_hir_node(hir_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::ForeignMod { .. }, @@ -39,26 +38,10 @@ pub(crate) fn validate_cmse_abi<'tcx>( ) .emit(); return; - }; - - if let Err((span, layout_err)) = - is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) - { - if should_emit_layout_error(abi, layout_err) { - dcx.emit_err(errors::CmseGeneric { span, abi }); - } - } - - if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, fn_ptr_ty.decl, abi) { - if should_emit_layout_error(abi, layout_err) { - let span = fn_ptr_ty.decl.output.span(); - dcx.emit_err(errors::CmseGeneric { span, abi }); - } } - } + }, ExternAbi::CmseNonSecureEntry => { - let hir_node = tcx.hir_node(hir_id); - let Some(hir::FnSig { decl, .. }) = hir_node.fn_sig() else { + let Some(hir::FnSig { decl, .. }) = tcx.hir_node(hir_id).fn_sig() else { // might happen when this ABI is used incorrectly. That will be handled elsewhere return; }; @@ -69,19 +52,21 @@ pub(crate) fn validate_cmse_abi<'tcx>( return; } - if let Err((span, layout_err)) = is_valid_cmse_inputs(tcx, dcx, fn_sig, decl, abi) { - if should_emit_layout_error(abi, layout_err) { - dcx.emit_err(errors::CmseGeneric { span, abi }); - } - } + decl + } + _ => return, + }; - if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, decl, abi) { - if should_emit_layout_error(abi, layout_err) { - dcx.emit_err(errors::CmseGeneric { span: decl.output.span(), abi }); - } - } + if let Err((span, layout_err)) = is_valid_cmse_inputs(tcx, dcx, fn_sig, fn_decl, abi) { + if should_emit_layout_error(abi, layout_err) { + dcx.emit_err(errors::CmseGeneric { span, abi }); + } + } + + if let Err(layout_err) = is_valid_cmse_output(tcx, dcx, fn_sig, fn_decl, abi) { + if should_emit_layout_error(abi, layout_err) { + dcx.emit_err(errors::CmseGeneric { span: fn_decl.output.span(), abi }); } - _ => (), } }