diff options
| author | Folkert de Vries <folkert@folkertdev.nl> | 2025-09-10 00:17:22 +0200 |
|---|---|---|
| committer | Folkert de Vries <folkert@folkertdev.nl> | 2025-09-11 10:18:48 +0200 |
| commit | fd48528d185f59f60e301bce1e01d670ff4bdb30 (patch) | |
| tree | 2fb3335987f19721fba3b61299552f4ddc477c70 | |
| parent | f4665ab8368ad2e8a86d4390ae35c28bdd9561bb (diff) | |
| download | rust-fd48528d185f59f60e301bce1e01d670ff4bdb30.tar.gz rust-fd48528d185f59f60e301bce1e01d670ff4bdb30.zip | |
c-variadic: allow inherent methods to be c-variadic
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 54 | ||||
| -rw-r--r-- | tests/ui/c-variadic/inherent-method.rs | 45 | ||||
| -rw-r--r-- | tests/ui/c-variadic/not-async.rs | 10 | ||||
| -rw-r--r-- | tests/ui/c-variadic/not-async.stderr | 30 | ||||
| -rw-r--r-- | tests/ui/c-variadic/trait-method.rs | 40 | ||||
| -rw-r--r-- | tests/ui/c-variadic/trait-method.stderr | 14 | ||||
| -rw-r--r-- | tests/ui/parser/variadic-ffi-semantic-restrictions.rs | 10 | ||||
| -rw-r--r-- | tests/ui/parser/variadic-ffi-semantic-restrictions.stderr | 20 |
8 files changed, 179 insertions, 44 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index a6ef89b553d..cdb3062c591 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -696,36 +696,38 @@ impl<'a> AstValidator<'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 }; diff --git a/tests/ui/c-variadic/inherent-method.rs b/tests/ui/c-variadic/inherent-method.rs new file mode 100644 index 00000000000..537bae7b3f0 --- /dev/null +++ b/tests/ui/c-variadic/inherent-method.rs @@ -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); + } +} diff --git a/tests/ui/c-variadic/not-async.rs b/tests/ui/c-variadic/not-async.rs index 45a7e1f8972..bdb51a9a432 100644 --- a/tests/ui/c-variadic/not-async.rs +++ b/tests/ui/c-variadic/not-async.rs @@ -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 +} diff --git a/tests/ui/c-variadic/not-async.stderr b/tests/ui/c-variadic/not-async.stderr index b8caf0d8bd8..eab4c4f0822 100644 --- a/tests/ui/c-variadic/not-async.stderr +++ b/tests/ui/c-variadic/not-async.stderr @@ -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[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 2 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/c-variadic/trait-method.rs b/tests/ui/c-variadic/trait-method.rs new file mode 100644 index 00000000000..4c468c1907b --- /dev/null +++ b/tests/ui/c-variadic/trait-method.rs @@ -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); + } +} diff --git a/tests/ui/c-variadic/trait-method.stderr b/tests/ui/c-variadic/trait-method.stderr new file mode 100644 index 00000000000..35f6e24ef71 --- /dev/null +++ b/tests/ui/c-variadic/trait-method.stderr @@ -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 + diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 4db056f15a5..566c4d30245 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -53,17 +53,17 @@ struct X; 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 } diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index 0cd78318de6..c18d857d14e 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -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 |
