about summary refs log tree commit diff
path: root/tests/ui/c-variadic/trait-method.rs
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-09-10 17:53:41 +0200
committerFolkert de Vries <folkert@folkertdev.nl>2025-09-11 10:27:28 +0200
commit01e83adc88653123fee444fdb930c16dd08da82d (patch)
tree625bc04a4365df1e7b897a2355d65ccfe8958b6c /tests/ui/c-variadic/trait-method.rs
parentfd48528d185f59f60e301bce1e01d670ff4bdb30 (diff)
downloadrust-01e83adc88653123fee444fdb930c16dd08da82d.tar.gz
rust-01e83adc88653123fee444fdb930c16dd08da82d.zip
c-variadic: allow trait methods to be c-variadic
but a C-variadic method makes a trait dyn-incompatible. That is because
methods from dyn traits, when cast to a function pointer, create a shim.
That shim can't really forward the c-variadic arguments.
Diffstat (limited to 'tests/ui/c-variadic/trait-method.rs')
-rw-r--r--tests/ui/c-variadic/trait-method.rs67
1 files changed, 50 insertions, 17 deletions
diff --git a/tests/ui/c-variadic/trait-method.rs b/tests/ui/c-variadic/trait-method.rs
index 4c468c1907b..97da0706a3a 100644
--- a/tests/ui/c-variadic/trait-method.rs
+++ b/tests/ui/c-variadic/trait-method.rs
@@ -1,40 +1,73 @@
-// For now C-variadic arguments in trait methods are rejected, though we aim to lift this
-// restriction in the future. In particular we need to think about the interaction with
-// `dyn Trait` and the `ReifyShim`s that it may generate for methods.
+//@ run-pass
 #![feature(c_variadic)]
-#![crate_type = "lib"]
-struct S;
 
-impl S {
+#[repr(transparent)]
+struct Struct(i32);
+
+impl Struct {
     unsafe extern "C" fn associated_function(mut ap: ...) -> i32 {
         unsafe { ap.arg() }
     }
 
     unsafe extern "C" fn method(&self, mut ap: ...) -> i32 {
-        unsafe { ap.arg() }
+        self.0 + unsafe { ap.arg::<i32>() }
     }
 }
 
-trait T {
+trait Trait: Sized {
+    fn get(&self) -> i32;
+
     unsafe extern "C" fn trait_associated_function(mut ap: ...) -> i32 {
-        //~^ ERROR: associated functions cannot have a C variable argument list
         unsafe { ap.arg() }
     }
 
-    unsafe extern "C" fn trait_method(&self, mut ap: ...) -> i32 {
-        //~^ ERROR: associated functions cannot have a C variable argument list
-        unsafe { ap.arg() }
+    unsafe extern "C" fn trait_method_owned(self, mut ap: ...) -> i32 {
+        self.get() + unsafe { ap.arg::<i32>() }
+    }
+
+    unsafe extern "C" fn trait_method_ref(&self, mut ap: ...) -> i32 {
+        self.get() + unsafe { ap.arg::<i32>() }
+    }
+
+    unsafe extern "C" fn trait_method_mut(&mut self, mut ap: ...) -> i32 {
+        self.get() + unsafe { ap.arg::<i32>() }
+    }
+
+    unsafe extern "C" fn trait_fat_pointer(self: Box<Self>, mut ap: ...) -> i32 {
+        self.get() + unsafe { ap.arg::<i32>() }
     }
 }
 
-impl T for S {}
+impl Trait for Struct {
+    fn get(&self) -> i32 {
+        self.0
+    }
+}
 
 fn main() {
     unsafe {
-        assert_eq!(S::associated_function(32), 32);
-        assert_eq!(S.method(32), 32);
+        assert_eq!(Struct::associated_function(32), 32);
+        assert_eq!(Struct(100).method(32), 132);
+
+        assert_eq!(Struct::trait_associated_function(32), 32);
+        assert_eq!(Struct(100).trait_method_owned(32), 132);
+        assert_eq!(Struct(100).trait_method_ref(32), 132);
+        assert_eq!(Struct(100).trait_method_mut(32), 132);
+        assert_eq!(Struct::trait_fat_pointer(Box::new(Struct(100)), 32), 132);
+
+        assert_eq!(<Struct as Trait>::trait_associated_function(32), 32);
+        assert_eq!(Trait::trait_method_owned(Struct(100), 32), 132);
+        assert_eq!(Trait::trait_method_ref(&Struct(100), 32), 132);
+        assert_eq!(Trait::trait_method_mut(&mut Struct(100), 32), 132);
+        assert_eq!(Trait::trait_fat_pointer(Box::new(Struct(100)), 32), 132);
+
+        type Associated = unsafe extern "C" fn(...) -> i32;
+        type Method<T> = unsafe extern "C" fn(T, ...) -> i32;
 
-        assert_eq!(S::trait_associated_function(32), 32);
-        assert_eq!(S.trait_method(32), 32);
+        assert_eq!((Struct::trait_associated_function as Associated)(32), 32);
+        assert_eq!((Struct::trait_method_owned as Method<_>)(Struct(100), 32), 132);
+        assert_eq!((Struct::trait_method_ref as Method<_>)(&Struct(100), 32), 132);
+        assert_eq!((Struct::trait_method_mut as Method<_>)(&mut Struct(100), 32), 132);
+        assert_eq!((Struct::trait_fat_pointer as Method<_>)(Box::new(Struct(100)), 32), 132);
     }
 }