diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-12-20 09:46:12 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-20 09:46:12 +0100 |
| commit | 8b3914ce4829f6d19ff76dbad7e648f78adf8dfd (patch) | |
| tree | 690676492d89ff7f506f12792caa40f7942fa036 /tests | |
| parent | f9c752d931c3ad05974765f796db33c6d72e21ea (diff) | |
| parent | 76b3e6de558cc67dca0098def00b0ee55dfc8d58 (diff) | |
| download | rust-8b3914ce4829f6d19ff76dbad7e648f78adf8dfd.tar.gz rust-8b3914ce4829f6d19ff76dbad7e648f78adf8dfd.zip | |
Rollup merge of #119094 - celinval:smir-layout, r=compiler-errors
Add function ABI and type layout to StableMIR This change introduces a new module to StableMIR named `abi` with information from `rustc_target::abi` and `rustc_abi`, that allow users to retrieve more low level information required to perform bit-precise analysis. The layout of a type can be retrieved via `Ty::layout`, and the instance ABI can be retrieved via `Instance::fn_abi()`. To properly handle errors while retrieve layout information, we had to implement a few layout related traits. r? ```@compiler-errors```
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/ui-fulldeps/stable-mir/check_abi.rs | 143 | ||||
| -rw-r--r-- | tests/ui-fulldeps/stable-mir/check_allocation.rs | 1 | ||||
| -rw-r--r-- | tests/ui-fulldeps/stable-mir/check_defs.rs | 6 |
3 files changed, 146 insertions, 4 deletions
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs new file mode 100644 index 00000000000..30b42bc3bfa --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -0,0 +1,143 @@ +// run-pass +//! Test information regarding type layout. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] +#![feature(ascii_char, ascii_char_variants)] + +extern crate rustc_hir; +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +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, CrateItem, CrateItems, ItemKind}; +use std::assert_matches::assert_matches; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +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(); + assert_eq!(fn_abi.conv, CallConvention::Rust); + assert_eq!(fn_abi.args.len(), 2); + + check_ignore(&fn_abi.args[0]); + 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()); + assert_eq!(abi.mode, PassMode::Ignore); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert!(layout.is_1zst()); +} + +/// Check the primitive argument: `primitive: char`. +fn check_primitive(abi: &ArgAbi) { + assert!(abi.ty.kind().is_char()); + assert_matches!(abi.mode, PassMode::Direct(_)); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert!(!layout.is_1zst()); + assert_matches!(layout.fields, FieldsShape::Primitive); +} + +/// Check the return value: `Result<usize, &str>`. +fn check_result(abi: ArgAbi) { + assert!(abi.ty.kind().is_enum()); + assert_matches!(abi.mode, PassMode::Indirect { .. }); + let layout = abi.layout.shape(); + assert!(layout.is_sized()); + assert_matches!(layout.fields, FieldsShape::Arbitrary { .. }); + assert_matches!(layout.variants, VariantsShape::Multiple { .. }) +} + +fn get_item<'a>( + items: &'a CrateItems, + item: (ItemKind, &str), +) -> Option<&'a stable_mir::CrateItem> { + items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1) +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "alloc_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + #![feature(c_variadic)] + #![allow(unused_variables)] + + pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{ + // We only care about the signature. + todo!() + }} + + + pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{ + 0 + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 8554630e9c9..7ce3597206b 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -209,7 +209,6 @@ fn check_len(item: CrateItem) { assert_eq!(alloc.read_uint(), Ok(2)); } -// Use internal API to find a function in a crate. fn get_item<'a>( items: &'a CrateItems, item: (ItemKind, &str), diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index ad667511332..e9a2599d873 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty { /// Check signature and type of `Vec::<u8>::new` and its generic version. fn test_vec_new(instance: mir::mono::Instance) { - let sig = instance.ty().kind().fn_sig().unwrap().skip_binder(); - assert_matches!(sig.inputs(), &[]); - let elem_ty = extract_elem_ty(sig.output()); + let sig = instance.fn_abi().unwrap(); + assert_eq!(&sig.args, &[]); + let elem_ty = extract_elem_ty(sig.ret.ty); assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8))); // Get the signature for Vec::<T>::new. |
