Skip to content

Commit

Permalink
fix ICE in CMSE type validation
Browse files Browse the repository at this point in the history
  • Loading branch information
folkertdev committed Sep 7, 2024
1 parent d678b81 commit 46115fd
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 13 deletions.
13 changes: 8 additions & 5 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub(crate) fn validate_cmse_abi<'tcx>(
abi: abi::Abi,
fn_sig: ty::PolyFnSig<'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);

if let abi::Abi::CCmseNonSecureCall = abi {
let hir_node = tcx.hir_node(hir_id);
let hir::Node::Ty(hir::Ty {
Expand Down Expand Up @@ -67,13 +70,13 @@ 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>,
fn_sig: ty::PolyFnSig<'tcx>,
fn_sig: ty::FnSig<'tcx>,
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
let mut span = None;
let mut accum = 0u64;

for (index, arg_def) in fn_sig.inputs().iter().enumerate() {
let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?;
for (index, ty) in fn_sig.inputs().iter().enumerate() {
let layout = tcx.layout_of(ParamEnv::reveal_all().and(*ty))?;

let align = layout.layout.align().abi.bytes();
let size = layout.layout.size().bytes();
Expand All @@ -96,9 +99,9 @@ fn is_valid_cmse_inputs<'tcx>(
/// Returns whether the output will fit into the available registers
fn is_valid_cmse_output<'tcx>(
tcx: TyCtxt<'tcx>,
fn_sig: ty::PolyFnSig<'tcx>,
fn_sig: ty::FnSig<'tcx>,
) -> Result<bool, &'tcx LayoutError<'tcx>> {
let mut ret_ty = fn_sig.output().skip_binder();
let mut ret_ty = fn_sig.output();
let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?;
let size = layout.layout.size().bytes();

Expand Down
25 changes: 23 additions & 2 deletions tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,31 @@ impl Copy for u32 {}
struct Wrapper<T>(T);

struct Test<T: Copy> {
f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64, //~ ERROR cannot find type `U` in this scope
//~^ ERROR function pointer types may not have generic parameters
f1: extern "C-cmse-nonsecure-call" fn<U: Copy>(U, u32, u32, u32) -> u64,
//~^ ERROR cannot find type `U` in this scope
//~| ERROR function pointer types may not have generic parameters
f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
//~^ ERROR `impl Trait` is not allowed in `fn` pointer parameters
f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64, //~ ERROR [E0798]
f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64, //~ ERROR [E0798]
}

type WithReference = extern "C-cmse-nonsecure-call" fn(&usize);

trait Trait {}
type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait;
//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798]

type WithStaticTraitObject =
extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait;
//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798]

#[repr(transparent)]
struct WrapperTransparent<'a>(&'a dyn Trait);

type WithTransparentTraitObject =
extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent;
//~^ ERROR return value of `"C-cmse-nonsecure-call"` function too large to pass via registers [E0798]

type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...);
//~^ ERROR C-variadic function must have a compatible calling convention, like `C` or `cdecl` [E0045]
45 changes: 39 additions & 6 deletions tests/ui/cmse-nonsecure/cmse-nonsecure-call/generics.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,59 @@ LL | struct Test<T: Copy, U> {
| +++

error[E0562]: `impl Trait` is not allowed in `fn` pointer parameters
--> $DIR/generics.rs:17:43
--> $DIR/generics.rs:18:43
|
LL | f2: extern "C-cmse-nonsecure-call" fn(impl Copy, u32, u32, u32) -> u64,
| ^^^^^^^^^
|
= note: `impl Trait` is only allowed in arguments and return types of functions and methods

error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
--> $DIR/generics.rs:19:9
--> $DIR/generics.rs:20:9
|
LL | f3: extern "C-cmse-nonsecure-call" fn(T, u32, u32, u32) -> u64,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0798]: function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
--> $DIR/generics.rs:20:9
--> $DIR/generics.rs:21:9
|
LL | f4: extern "C-cmse-nonsecure-call" fn(Wrapper<T>, u32, u32, u32) -> u64,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 5 previous errors
error[E0798]: return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/generics.rs:27:73
|
LL | type WithTraitObject = extern "C-cmse-nonsecure-call" fn(&dyn Trait) -> &dyn Trait;
| ^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"C-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 `"C-cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/generics.rs:31:62
|
LL | extern "C-cmse-nonsecure-call" fn(&'static dyn Trait) -> &'static dyn Trait;
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"C-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 `"C-cmse-nonsecure-call"` function too large to pass via registers
--> $DIR/generics.rs:38:62
|
LL | extern "C-cmse-nonsecure-call" fn(WrapperTransparent) -> WrapperTransparent;
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"C-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[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
--> $DIR/generics.rs:41:20
|
LL | type WithVarArgs = extern "C-cmse-nonsecure-call" fn(u32, ...);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention

error: aborting due to 9 previous errors

Some errors have detailed explanations: E0412, E0562, E0798.
For more information about an error, try `rustc --explain E0412`.
Some errors have detailed explanations: E0045, E0412, E0562, E0798.
For more information about an error, try `rustc --explain E0045`.

0 comments on commit 46115fd

Please sign in to comment.