c-variadic: allow inherent methods to be c-variadic

This commit is contained in:
Folkert de Vries
2025-09-10 00:17:22 +02:00
parent f4665ab836
commit fd48528d18
8 changed files with 179 additions and 44 deletions
+28 -26
View File
@@ -696,36 +696,38 @@ fn check_c_variadic_type(&self, fk: FnKind<'a>) {
match fn_ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free => match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: variadic_param.span,
abi: symbol_unescaped,
extern_span: sig.extern_span(),
});
FnCtxt::Free | FnCtxt::Assoc(AssocCtxt::Impl { of_trait: false }) => {
match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: variadic_param.span,
abi: symbol_unescaped,
extern_span: sig.extern_span(),
});
}
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
}
},
}
FnCtxt::Assoc(_) => {
// For now, C variable argument lists are unsupported in associated functions.
let err = errors::CVariadicAssociatedFunction { span: variadic_param.span };
+45
View File
@@ -0,0 +1,45 @@
//@ run-pass
#![feature(c_variadic)]
#[repr(transparent)]
struct S(i32);
impl S {
unsafe extern "C" fn associated_function(mut ap: ...) -> i32 {
unsafe { ap.arg() }
}
unsafe extern "C" fn method_owned(self, mut ap: ...) -> i32 {
self.0 + unsafe { ap.arg::<i32>() }
}
unsafe extern "C" fn method_ref(&self, mut ap: ...) -> i32 {
self.0 + unsafe { ap.arg::<i32>() }
}
unsafe extern "C" fn method_mut(&mut self, mut ap: ...) -> i32 {
self.0 + unsafe { ap.arg::<i32>() }
}
unsafe extern "C" fn fat_pointer(self: Box<Self>, mut ap: ...) -> i32 {
self.0 + unsafe { ap.arg::<i32>() }
}
}
fn main() {
unsafe {
assert_eq!(S::associated_function(32), 32);
assert_eq!(S(100).method_owned(32), 132);
assert_eq!(S(100).method_ref(32), 132);
assert_eq!(S(100).method_mut(32), 132);
assert_eq!(S::fat_pointer(Box::new(S(100)), 32), 132);
type Method<T> = unsafe extern "C" fn(T, ...) -> i32;
assert_eq!((S::associated_function as unsafe extern "C" fn(...) -> i32)(32), 32);
assert_eq!((S::method_owned as Method<_>)(S(100), 32), 132);
assert_eq!((S::method_ref as Method<_>)(&S(100), 32), 132);
assert_eq!((S::method_mut as Method<_>)(&mut S(100), 32), 132);
assert_eq!((S::fat_pointer as Method<_>)(Box::new(S(100)), 32), 132);
}
}
+9 -1
View File
@@ -2,6 +2,14 @@
#![feature(c_variadic)]
#![crate_type = "lib"]
async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
//~^ ERROR functions cannot be both `async` and C-variadic
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
struct S;
impl S {
async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
//~^ ERROR functions cannot be both `async` and C-variadic
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
}
+23 -7
View File
@@ -1,19 +1,35 @@
error: functions cannot be both `async` and C-variadic
--> $DIR/not-async.rs:5:1
|
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
| ^^^^^ `async` because of this ^^^ C-variadic because of this
LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
| ^^^^^ `async` because of this ^^^ C-variadic because of this
error: functions cannot be both `async` and C-variadic
--> $DIR/not-async.rs:12:5
|
LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
| ^^^^^ `async` because of this ^^^ C-variadic because of this
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
--> $DIR/not-async.rs:5:59
--> $DIR/not-async.rs:5:62
|
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
| --------------------------------------------------------- ^^
LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
| ------------------------------------------------------------ ^^
| |
| opaque type defined here
|
= note: hidden type `{async fn body of cannot_be_async()}` captures lifetime `'_`
= note: hidden type `{async fn body of fn_cannot_be_async()}` captures lifetime `'_`
error: aborting due to 2 previous errors
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
--> $DIR/not-async.rs:12:70
|
LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
| ---------------------------------------------------------------- ^^
| |
| opaque type defined here
|
= note: hidden type `{async fn body of S::method_cannot_be_async()}` captures lifetime `'_`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0700`.
+40
View File
@@ -0,0 +1,40 @@
// 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.
#![feature(c_variadic)]
#![crate_type = "lib"]
struct S;
impl S {
unsafe extern "C" fn associated_function(mut ap: ...) -> i32 {
unsafe { ap.arg() }
}
unsafe extern "C" fn method(&self, mut ap: ...) -> i32 {
unsafe { ap.arg() }
}
}
trait T {
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() }
}
}
impl T for S {}
fn main() {
unsafe {
assert_eq!(S::associated_function(32), 32);
assert_eq!(S.method(32), 32);
assert_eq!(S::trait_associated_function(32), 32);
assert_eq!(S.trait_method(32), 32);
}
}
+14
View File
@@ -0,0 +1,14 @@
error: associated functions cannot have a C variable argument list
--> $DIR/trait-method.rs:19:52
|
LL | unsafe extern "C" fn trait_associated_function(mut ap: ...) -> i32 {
| ^^^^^^^^^^^
error: associated functions cannot have a C variable argument list
--> $DIR/trait-method.rs:24:46
|
LL | unsafe extern "C" fn trait_method(&self, mut ap: ...) -> i32 {
| ^^^^^^^^^^^
error: aborting due to 2 previous errors
@@ -53,17 +53,17 @@ extern "C" fn f3_3(..., x: isize) {}
impl X {
fn i_f1(x: isize, ...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn i_f2(...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn i_f3(..., x: isize, ...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
//~| ERROR `...` must be the last argument of a C-variadic function
fn i_f4(..., x: isize, ...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
//~| ERROR `...` must be the last argument of a C-variadic function
const fn i_f5(x: isize, ...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
//~| ERROR functions cannot be both `const` and C-variadic
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
}
@@ -132,17 +132,21 @@ error: `...` must be the last argument of a C-variadic function
LL | fn e_f2(..., x: isize);
| ^^^
error: associated functions cannot have a C variable argument list
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:55:23
|
LL | fn i_f1(x: isize, ...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: associated functions cannot have a C variable argument list
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:57:13
|
LL | fn i_f2(...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
@@ -150,11 +154,13 @@ error: `...` must be the last argument of a C-variadic function
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
error: associated functions cannot have a C variable argument list
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
|
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:13
@@ -162,11 +168,13 @@ error: `...` must be the last argument of a C-variadic function
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
error: associated functions cannot have a C variable argument list
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:28
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:5
@@ -176,11 +184,13 @@ LL | const fn i_f5(x: isize, ...) {}
| |
| `const` because of this
error: associated functions cannot have a C variable argument list
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:72:23