diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 46ae0929bcd4a..632e97b32f520 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -66,11 +66,14 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> { type T = FnAbi; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + assert!(self.args.len() >= self.fixed_count as usize); + assert!(!self.c_variadic || matches!(self.conv, Conv::C)); FnAbi { args: self.args.as_ref().stable(tables), ret: self.ret.stable(tables), fixed_count: self.fixed_count, conv: self.conv.stable(tables), + c_variadic: self.c_variadic, } } } @@ -122,10 +125,20 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode { fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { match self { rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, - rustc_target::abi::call::PassMode::Direct(_) => PassMode::Direct, - rustc_target::abi::call::PassMode::Pair(_, _) => PassMode::Pair, - rustc_target::abi::call::PassMode::Cast { .. } => PassMode::Cast, - rustc_target::abi::call::PassMode::Indirect { .. } => PassMode::Indirect, + rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)), + rustc_target::abi::call::PassMode::Pair(first, second) => { + PassMode::Pair(opaque(first), opaque(second)) + } + rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => { + PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) } + } + rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => { + PassMode::Indirect { + attrs: opaque(attrs), + meta_attrs: opaque(meta_attrs), + on_stack: *on_stack, + } + } } } } diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index d4e8e874c1f98..53dac6abefb30 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -21,12 +21,9 @@ pub struct FnAbi { /// The ABI convention. pub conv: CallConvention, -} -impl FnAbi { - pub fn is_c_variadic(&self) -> bool { - self.args.len() > self.fixed_count as usize - } + /// Whether this is a variadic C function, + pub c_variadic: bool, } /// Information about the ABI of a function's argument, or return value. @@ -47,15 +44,15 @@ pub enum PassMode { /// Pass the argument directly. /// /// The argument has a layout abi of `Scalar` or `Vector`. - Direct, + Direct(Opaque), /// Pass a pair's elements directly in two arguments. /// /// The argument has a layout abi of `ScalarPair`. - Pair, + Pair(Opaque, Opaque), /// Pass the argument after casting it. - Cast, + Cast { pad_i32: bool, cast: Opaque }, /// Pass the argument indirectly via a hidden pointer. - Indirect, + Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool }, } /// The layout of a type, alongside the type itself. diff --git a/tests/ui-fulldeps/stable-mir/check_layout.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs similarity index 79% rename from tests/ui-fulldeps/stable-mir/check_layout.rs rename to tests/ui-fulldeps/stable-mir/check_abi.rs index 1c33103b0feed..30b42bc3bfafc 100644 --- a/tests/ui-fulldeps/stable-mir/check_layout.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; use stable_mir::mir::mono::Instance; -use stable_mir::{CrateDef, CrateItems, ItemKind}; +use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind}; use std::assert_matches::assert_matches; use std::convert::TryFrom; use std::io::Write; @@ -35,6 +35,8 @@ const CRATE_NAME: &str = "input"; fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); + + // Test fn_abi let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap(); let instance = Instance::try_from(target_fn).unwrap(); let fn_abi = instance.fn_abi().unwrap(); @@ -45,9 +47,26 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { check_primitive(&fn_abi.args[1]); check_result(fn_abi.ret); + // Test variadic function. + let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap(); + check_variadic(variadic_fn); + ControlFlow::Continue(()) } +/// Check the variadic function ABI: +/// ```no_run +/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize { +/// 0 +/// } +/// ``` +fn check_variadic(variadic_fn: CrateItem) { + let instance = Instance::try_from(variadic_fn).unwrap(); + let abi = instance.fn_abi().unwrap(); + assert!(abi.c_variadic); + assert_eq!(abi.args.len(), 1); +} + /// Check the argument to be ignored: `ignore: [u8; 0]`. fn check_ignore(abi: &ArgAbi) { assert!(abi.ty.kind().is_array()); @@ -60,7 +79,7 @@ fn check_ignore(abi: &ArgAbi) { /// Check the primitive argument: `primitive: char`. fn check_primitive(abi: &ArgAbi) { assert!(abi.ty.kind().is_char()); - assert_eq!(abi.mode, PassMode::Direct); + assert_matches!(abi.mode, PassMode::Direct(_)); let layout = abi.layout.shape(); assert!(layout.is_sized()); assert!(!layout.is_1zst()); @@ -70,7 +89,7 @@ fn check_primitive(abi: &ArgAbi) { /// Check the return value: `Result`. fn check_result(abi: ArgAbi) { assert!(abi.ty.kind().is_enum()); - assert_eq!(abi.mode, PassMode::Indirect); + assert_matches!(abi.mode, PassMode::Indirect { .. }); let layout = abi.layout.shape(); assert!(layout.is_sized()); assert_matches!(layout.fields, FieldsShape::Arbitrary { .. }); @@ -106,11 +125,18 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" - #[allow(unused_variables)] + #![feature(c_variadic)] + #![allow(unused_variables)] + pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result {{ // We only care about the signature. todo!() }} + + + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ + 0 + }} "# )?; Ok(())