about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCelina G. Val <celinval@amazon.com>2023-12-19 11:04:34 -0800
committerCelina G. Val <celinval@amazon.com>2023-12-19 11:04:34 -0800
commit76b3e6de558cc67dca0098def00b0ee55dfc8d58 (patch)
treeb36ed88fc8cd527128cf735a91476f654418bd7d
parent1a83c5b55bdad84baca69d121d9c3e6f357e8570 (diff)
downloadrust-76b3e6de558cc67dca0098def00b0ee55dfc8d58.tar.gz
rust-76b3e6de558cc67dca0098def00b0ee55dfc8d58.zip
Fix c_variadic flag and add opaque info to PassMode
We should expand the information in PassMode later.
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs21
-rw-r--r--compiler/stable_mir/src/abi.rs15
-rw-r--r--tests/ui-fulldeps/stable-mir/check_abi.rs (renamed from tests/ui-fulldeps/stable-mir/check_layout.rs)34
3 files changed, 53 insertions, 17 deletions
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 46ae0929bcd..632e97b32f5 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 d4e8e874c1f..53dac6abefb 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
index 1c33103b0fe..30b42bc3bfa 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<usize, &str>`.
 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<usize, &'static str> {{
             // We only care about the signature.
             todo!()
         }}
+
+
+        pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
+            0
+        }}
         "#
     )?;
     Ok(())