Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
.label = `extern "{$abi}"` because of this
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
Expand Down
7 changes: 1 addition & 6 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ impl<'a> AstValidator<'a> {

match fn_ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free => match sig.header.ext {
FnCtxt::Free | FnCtxt::Assoc(_) => match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
Expand Down Expand Up @@ -726,11 +726,6 @@ impl<'a> AstValidator<'a> {
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 };
self.dcx().emit_err(err);
}
}
}

Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,13 +318,6 @@ pub(crate) struct ExternItemAscii {
pub block: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_associated_function)]
pub(crate) struct CVariadicAssociatedFunction {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_no_extern)]
#[help]
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,9 @@ impl DynCompatibilityViolation {
DynCompatibilityViolation::Method(name, MethodViolationCode::AsyncFn, _) => {
format!("method `{name}` is `async`").into()
}
DynCompatibilityViolation::Method(name, MethodViolationCode::CVariadic, _) => {
format!("method `{name}` is C-variadic").into()
}
DynCompatibilityViolation::Method(
name,
MethodViolationCode::WhereClauseReferencesSelf,
Expand Down Expand Up @@ -977,6 +980,9 @@ pub enum MethodViolationCode {
/// e.g., `fn foo<A>()`
Generic,

/// e.g., `fn (mut ap: ...)`
CVariadic,

/// the method's receiver (`self` argument) can't be dispatched on
UndispatchableReceiver(Option<Span>),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ fn virtual_call_violations_for_method<'tcx>(
if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) {
errors.push(code);
}
if sig.skip_binder().c_variadic {
errors.push(MethodViolationCode::CVariadic);
}

// We can't monomorphize things like `fn foo<A>(...)`.
let own_counts = tcx.generics_of(method.def_id).own_counts();
Expand Down
45 changes: 45 additions & 0 deletions tests/ui/c-variadic/inherent-method.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
10 changes: 9 additions & 1 deletion tests/ui/c-variadic/not-async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
30 changes: 23 additions & 7 deletions tests/ui/c-variadic/not-async.stderr
Original file line number Diff line number Diff line change
@@ -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`.
35 changes: 35 additions & 0 deletions tests/ui/c-variadic/not-dyn-compatible.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Traits where a method is c-variadic are not dyn compatible.
//
// Creating a function pointer from a method on an `&dyn T` value creates a ReifyShim.
// This shim cannot reliably forward C-variadic arguments. Thus the trait as a whole
// is dyn-incompatible to prevent invalid shims from being created.
#![feature(c_variadic)]

#[repr(transparent)]
struct Struct(u64);

trait Trait {
fn get(&self) -> u64;

unsafe extern "C" fn dyn_method_ref(&self, mut ap: ...) -> u64 {
self.get() + unsafe { ap.arg::<u64>() }
}
}

impl Trait for Struct {
fn get(&self) -> u64 {
self.0
}
}

fn main() {
unsafe {
let dyn_object: &dyn Trait = &Struct(64);
//~^ ERROR the trait `Trait` is not dyn compatible
assert_eq!(dyn_object.dyn_method_ref(100), 164);
assert_eq!(
(Trait::dyn_method_ref as unsafe extern "C" fn(_, ...) -> u64)(dyn_object, 100),
164
);
}
}
21 changes: 21 additions & 0 deletions tests/ui/c-variadic/not-dyn-compatible.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0038]: the trait `Trait` is not dyn compatible
--> $DIR/not-dyn-compatible.rs:27:30
|
LL | let dyn_object: &dyn Trait = &Struct(64);
| ^^^^^ `Trait` is not dyn compatible
|
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/not-dyn-compatible.rs:14:26
|
LL | trait Trait {
| ----- this trait is not dyn compatible...
...
LL | unsafe extern "C" fn dyn_method_ref(&self, mut ap: ...) -> u64 {
| ^^^^^^^^^^^^^^ ...because method `dyn_method_ref` is C-variadic
= help: consider moving `dyn_method_ref` to another trait
= help: only type `Struct` implements `Trait`; consider using it directly instead.

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0038`.
73 changes: 73 additions & 0 deletions tests/ui/c-variadic/trait-method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//@ run-pass
#![feature(c_variadic)]

#[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 {
self.0 + unsafe { ap.arg::<i32>() }
}
}

trait Trait: Sized {
fn get(&self) -> i32;

unsafe extern "C" fn trait_associated_function(mut ap: ...) -> i32 {
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 Trait for Struct {
fn get(&self) -> i32 {
self.0
}
}

fn main() {
unsafe {
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!((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);
}
}
1 change: 0 additions & 1 deletion tests/ui/feature-gates/feature-gate-c_variadic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ pub unsafe extern "C" fn test(_: i32, ap: ...) {}
trait Trait {
unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
//~^ ERROR C-variadic functions are unstable
//~| ERROR associated functions cannot have a C variable argument list
}
8 changes: 1 addition & 7 deletions tests/ui/feature-gates/feature-gate-c_variadic.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
error: associated functions cannot have a C variable argument list
--> $DIR/feature-gate-c_variadic.rs:7:45
|
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
| ^^^^^^^

error[E0658]: C-variadic functions are unstable
--> $DIR/feature-gate-c_variadic.rs:3:1
|
Expand All @@ -24,6 +18,6 @@ LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
= help: add `#![feature(c_variadic)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
18 changes: 9 additions & 9 deletions tests/ui/parser/variadic-ffi-semantic-restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,30 @@ 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
}

trait T {
fn t_f1(x: isize, ...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn t_f2(x: isize, ...);
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn t_f3(...) {}
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn t_f4(...);
//~^ ERROR associated functions cannot have a C variable argument list
//~^ ERROR `...` is not supported for non-extern functions
fn t_f5(..., x: isize) {}
//~^ ERROR `...` must be the last argument of a C-variadic function
fn t_f6(..., x: isize);
Expand Down
Loading
Loading