Skip to content

Commit fd48528

Browse files
committed
c-variadic: allow inherent methods to be c-variadic
1 parent f4665ab commit fd48528

File tree

8 files changed

+179
-44
lines changed

8 files changed

+179
-44
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -696,36 +696,38 @@ impl<'a> AstValidator<'a> {
696696

697697
match fn_ctxt {
698698
FnCtxt::Foreign => return,
699-
FnCtxt::Free => match sig.header.ext {
700-
Extern::Implicit(_) => {
701-
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
702-
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
703-
span: variadic_param.span,
704-
unsafe_span: sig.safety_span(),
705-
});
706-
}
707-
}
708-
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
709-
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
710-
self.dcx().emit_err(errors::CVariadicBadExtern {
711-
span: variadic_param.span,
712-
abi: symbol_unescaped,
713-
extern_span: sig.extern_span(),
714-
});
699+
FnCtxt::Free | FnCtxt::Assoc(AssocCtxt::Impl { of_trait: false }) => {
700+
match sig.header.ext {
701+
Extern::Implicit(_) => {
702+
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
703+
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
704+
span: variadic_param.span,
705+
unsafe_span: sig.safety_span(),
706+
});
707+
}
715708
}
709+
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
710+
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
711+
self.dcx().emit_err(errors::CVariadicBadExtern {
712+
span: variadic_param.span,
713+
abi: symbol_unescaped,
714+
extern_span: sig.extern_span(),
715+
});
716+
}
716717

717-
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
718-
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
719-
span: variadic_param.span,
720-
unsafe_span: sig.safety_span(),
721-
});
718+
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
719+
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
720+
span: variadic_param.span,
721+
unsafe_span: sig.safety_span(),
722+
});
723+
}
724+
}
725+
Extern::None => {
726+
let err = errors::CVariadicNoExtern { span: variadic_param.span };
727+
self.dcx().emit_err(err);
722728
}
723729
}
724-
Extern::None => {
725-
let err = errors::CVariadicNoExtern { span: variadic_param.span };
726-
self.dcx().emit_err(err);
727-
}
728-
},
730+
}
729731
FnCtxt::Assoc(_) => {
730732
// For now, C variable argument lists are unsupported in associated functions.
731733
let err = errors::CVariadicAssociatedFunction { span: variadic_param.span };
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//@ run-pass
2+
#![feature(c_variadic)]
3+
4+
#[repr(transparent)]
5+
struct S(i32);
6+
7+
impl S {
8+
unsafe extern "C" fn associated_function(mut ap: ...) -> i32 {
9+
unsafe { ap.arg() }
10+
}
11+
12+
unsafe extern "C" fn method_owned(self, mut ap: ...) -> i32 {
13+
self.0 + unsafe { ap.arg::<i32>() }
14+
}
15+
16+
unsafe extern "C" fn method_ref(&self, mut ap: ...) -> i32 {
17+
self.0 + unsafe { ap.arg::<i32>() }
18+
}
19+
20+
unsafe extern "C" fn method_mut(&mut self, mut ap: ...) -> i32 {
21+
self.0 + unsafe { ap.arg::<i32>() }
22+
}
23+
24+
unsafe extern "C" fn fat_pointer(self: Box<Self>, mut ap: ...) -> i32 {
25+
self.0 + unsafe { ap.arg::<i32>() }
26+
}
27+
}
28+
29+
fn main() {
30+
unsafe {
31+
assert_eq!(S::associated_function(32), 32);
32+
assert_eq!(S(100).method_owned(32), 132);
33+
assert_eq!(S(100).method_ref(32), 132);
34+
assert_eq!(S(100).method_mut(32), 132);
35+
assert_eq!(S::fat_pointer(Box::new(S(100)), 32), 132);
36+
37+
type Method<T> = unsafe extern "C" fn(T, ...) -> i32;
38+
39+
assert_eq!((S::associated_function as unsafe extern "C" fn(...) -> i32)(32), 32);
40+
assert_eq!((S::method_owned as Method<_>)(S(100), 32), 132);
41+
assert_eq!((S::method_ref as Method<_>)(&S(100), 32), 132);
42+
assert_eq!((S::method_mut as Method<_>)(&mut S(100), 32), 132);
43+
assert_eq!((S::fat_pointer as Method<_>)(Box::new(S(100)), 32), 132);
44+
}
45+
}

tests/ui/c-variadic/not-async.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
#![feature(c_variadic)]
33
#![crate_type = "lib"]
44

5-
async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
5+
async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
66
//~^ ERROR functions cannot be both `async` and C-variadic
77
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
8+
9+
struct S;
10+
11+
impl S {
12+
async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
13+
//~^ ERROR functions cannot be both `async` and C-variadic
14+
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
15+
}
Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
11
error: functions cannot be both `async` and C-variadic
22
--> $DIR/not-async.rs:5:1
33
|
4-
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
5-
| ^^^^^ `async` because of this ^^^ C-variadic because of this
4+
LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
5+
| ^^^^^ `async` because of this ^^^ C-variadic because of this
6+
7+
error: functions cannot be both `async` and C-variadic
8+
--> $DIR/not-async.rs:12:5
9+
|
10+
LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
11+
| ^^^^^ `async` because of this ^^^ C-variadic because of this
612

713
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
8-
--> $DIR/not-async.rs:5:59
14+
--> $DIR/not-async.rs:5:62
915
|
10-
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
11-
| --------------------------------------------------------- ^^
16+
LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, ...) {}
17+
| ------------------------------------------------------------ ^^
1218
| |
1319
| opaque type defined here
1420
|
15-
= note: hidden type `{async fn body of cannot_be_async()}` captures lifetime `'_`
21+
= note: hidden type `{async fn body of fn_cannot_be_async()}` captures lifetime `'_`
22+
23+
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
24+
--> $DIR/not-async.rs:12:70
25+
|
26+
LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, ...) {}
27+
| ---------------------------------------------------------------- ^^
28+
| |
29+
| opaque type defined here
30+
|
31+
= note: hidden type `{async fn body of S::method_cannot_be_async()}` captures lifetime `'_`
1632

17-
error: aborting due to 2 previous errors
33+
error: aborting due to 4 previous errors
1834

1935
For more information about this error, try `rustc --explain E0700`.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// For now C-variadic arguments in trait methods are rejected, though we aim to lift this
2+
// restriction in the future. In particular we need to think about the interaction with
3+
// `dyn Trait` and the `ReifyShim`s that it may generate for methods.
4+
#![feature(c_variadic)]
5+
#![crate_type = "lib"]
6+
struct S;
7+
8+
impl S {
9+
unsafe extern "C" fn associated_function(mut ap: ...) -> i32 {
10+
unsafe { ap.arg() }
11+
}
12+
13+
unsafe extern "C" fn method(&self, mut ap: ...) -> i32 {
14+
unsafe { ap.arg() }
15+
}
16+
}
17+
18+
trait T {
19+
unsafe extern "C" fn trait_associated_function(mut ap: ...) -> i32 {
20+
//~^ ERROR: associated functions cannot have a C variable argument list
21+
unsafe { ap.arg() }
22+
}
23+
24+
unsafe extern "C" fn trait_method(&self, mut ap: ...) -> i32 {
25+
//~^ ERROR: associated functions cannot have a C variable argument list
26+
unsafe { ap.arg() }
27+
}
28+
}
29+
30+
impl T for S {}
31+
32+
fn main() {
33+
unsafe {
34+
assert_eq!(S::associated_function(32), 32);
35+
assert_eq!(S.method(32), 32);
36+
37+
assert_eq!(S::trait_associated_function(32), 32);
38+
assert_eq!(S.trait_method(32), 32);
39+
}
40+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: associated functions cannot have a C variable argument list
2+
--> $DIR/trait-method.rs:19:52
3+
|
4+
LL | unsafe extern "C" fn trait_associated_function(mut ap: ...) -> i32 {
5+
| ^^^^^^^^^^^
6+
7+
error: associated functions cannot have a C variable argument list
8+
--> $DIR/trait-method.rs:24:46
9+
|
10+
LL | unsafe extern "C" fn trait_method(&self, mut ap: ...) -> i32 {
11+
| ^^^^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+

tests/ui/parser/variadic-ffi-semantic-restrictions.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ struct X;
5353

5454
impl X {
5555
fn i_f1(x: isize, ...) {}
56-
//~^ ERROR associated functions cannot have a C variable argument list
56+
//~^ ERROR `...` is not supported for non-extern functions
5757
fn i_f2(...) {}
58-
//~^ ERROR associated functions cannot have a C variable argument list
58+
//~^ ERROR `...` is not supported for non-extern functions
5959
fn i_f3(..., x: isize, ...) {}
60-
//~^ ERROR associated functions cannot have a C variable argument list
60+
//~^ ERROR `...` is not supported for non-extern functions
6161
//~| ERROR `...` must be the last argument of a C-variadic function
6262
fn i_f4(..., x: isize, ...) {}
63-
//~^ ERROR associated functions cannot have a C variable argument list
63+
//~^ ERROR `...` is not supported for non-extern functions
6464
//~| ERROR `...` must be the last argument of a C-variadic function
6565
const fn i_f5(x: isize, ...) {}
66-
//~^ ERROR associated functions cannot have a C variable argument list
66+
//~^ ERROR `...` is not supported for non-extern functions
6767
//~| ERROR functions cannot be both `const` and C-variadic
6868
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
6969
}

tests/ui/parser/variadic-ffi-semantic-restrictions.stderr

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,41 +132,49 @@ error: `...` must be the last argument of a C-variadic function
132132
LL | fn e_f2(..., x: isize);
133133
| ^^^
134134

135-
error: associated functions cannot have a C variable argument list
135+
error: `...` is not supported for non-extern functions
136136
--> $DIR/variadic-ffi-semantic-restrictions.rs:55:23
137137
|
138138
LL | fn i_f1(x: isize, ...) {}
139139
| ^^^
140+
|
141+
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
140142

141-
error: associated functions cannot have a C variable argument list
143+
error: `...` is not supported for non-extern functions
142144
--> $DIR/variadic-ffi-semantic-restrictions.rs:57:13
143145
|
144146
LL | fn i_f2(...) {}
145147
| ^^^
148+
|
149+
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
146150

147151
error: `...` must be the last argument of a C-variadic function
148152
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
149153
|
150154
LL | fn i_f3(..., x: isize, ...) {}
151155
| ^^^
152156

153-
error: associated functions cannot have a C variable argument list
157+
error: `...` is not supported for non-extern functions
154158
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
155159
|
156160
LL | fn i_f3(..., x: isize, ...) {}
157161
| ^^^
162+
|
163+
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
158164

159165
error: `...` must be the last argument of a C-variadic function
160166
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:13
161167
|
162168
LL | fn i_f4(..., x: isize, ...) {}
163169
| ^^^
164170

165-
error: associated functions cannot have a C variable argument list
171+
error: `...` is not supported for non-extern functions
166172
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:28
167173
|
168174
LL | fn i_f4(..., x: isize, ...) {}
169175
| ^^^
176+
|
177+
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
170178

171179
error: functions cannot be both `const` and C-variadic
172180
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:5
@@ -176,11 +184,13 @@ LL | const fn i_f5(x: isize, ...) {}
176184
| |
177185
| `const` because of this
178186

179-
error: associated functions cannot have a C variable argument list
187+
error: `...` is not supported for non-extern functions
180188
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
181189
|
182190
LL | const fn i_f5(x: isize, ...) {}
183191
| ^^^
192+
|
193+
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
184194

185195
error: associated functions cannot have a C variable argument list
186196
--> $DIR/variadic-ffi-semantic-restrictions.rs:72:23

0 commit comments

Comments
 (0)