Skip to content

Commit a8cde8a

Browse files
committed
c-variadic: reject non-unsafe functions
1 parent 5de9bc7 commit a8cde8a

File tree

6 files changed

+96
-21
lines changed

6 files changed

+96
-21
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2309,6 +2309,27 @@ impl FnSig {
23092309

23102310
self.span.shrink_to_lo()
23112311
}
2312+
2313+
/// The span of the header's safety, or where to insert it if empty.
2314+
pub fn safety_span(&self) -> Span {
2315+
match self.header.safety {
2316+
Safety::Unsafe(span) | Safety::Safe(span) => span,
2317+
Safety::Default => {
2318+
// Insert after the `coroutine_kind` if available.
2319+
if let Some(coroutine_kind) = self.header.coroutine_kind {
2320+
return coroutine_kind.span().shrink_to_hi();
2321+
}
2322+
2323+
// Insert after the `const` keyword if available.
2324+
if let Const::Yes(const_span) = self.header.constness {
2325+
return const_span.shrink_to_hi();
2326+
}
2327+
2328+
// Insert right at the front of the signature.
2329+
self.span.shrink_to_lo()
2330+
}
2331+
}
2332+
}
23122333
}
23132334

23142335
/// A constraint on an associated item.

compiler/rustc_ast_passes/messages.ftl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
6868
6969
ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list
7070
71+
ast_passes_c_variadic_must_be_unsafe =
72+
functions with a C variable argument list must be unsafe
73+
.suggestion = add the `unsafe` keyword to this definition
74+
7175
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
7276
7377
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -698,20 +698,25 @@ impl<'a> AstValidator<'a> {
698698
FnCtxt::Foreign => return,
699699
FnCtxt::Free => match sig.header.ext {
700700
Extern::Implicit(_) => {
701-
if matches!(sig.header.safety, Safety::Unsafe(_)) {
702-
return;
701+
// Implicitly defaults to C.
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+
});
703707
}
704-
705-
self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
706708
}
707709
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
708-
if matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
709-
if matches!(sig.header.safety, Safety::Unsafe(_)) {
710-
return;
711-
}
710+
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
711+
self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
712712
}
713713

714-
self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
714+
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
715+
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
716+
span: variadic_param.span,
717+
unsafe_span: sig.safety_span(),
718+
});
719+
}
715720
}
716721
Extern::None => {
717722
let err = errors::CVariadicNoExtern { span: variadic_param.span };

compiler/rustc_ast_passes/src/errors.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,21 @@ pub(crate) struct CVariadicNoExtern {
332332
pub span: Span,
333333
}
334334

335+
#[derive(Diagnostic)]
336+
#[diag(ast_passes_c_variadic_must_be_unsafe)]
337+
pub(crate) struct CVariadicMustBeUnsafe {
338+
#[primary_span]
339+
pub span: Span,
340+
341+
#[suggestion(
342+
ast_passes_suggestion,
343+
applicability = "maybe-incorrect",
344+
code = "unsafe ",
345+
style = "verbose"
346+
)]
347+
pub unsafe_span: Span,
348+
}
349+
335350
#[derive(Diagnostic)]
336351
#[diag(ast_passes_bad_c_variadic)]
337352
pub(crate) struct BadCVariadic {

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ fn f1_2(...) {}
1010
//~^ ERROR `...` is not supported for non-extern functions
1111

1212
extern "C" fn f2_1(x: isize, ...) {}
13-
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
13+
//~^ ERROR functions with a C variable argument list must be unsafe
1414

1515
extern "C" fn f2_2(...) {}
16-
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
16+
//~^ ERROR functions with a C variable argument list must be unsafe
1717

1818
extern "C" fn f2_3(..., x: isize) {}
1919
//~^ ERROR `...` must be the last argument of a C-variadic function
2020

2121
extern "C" fn f3_1(x: isize, ...) {}
22-
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
22+
//~^ ERROR functions with a C variable argument list must be unsafe
2323

2424
extern "C" fn f3_2(...) {}
25-
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
25+
//~^ ERROR functions with a C variable argument list must be unsafe
2626

2727
extern "C" fn f3_3(..., x: isize) {}
2828
//~^ ERROR `...` must be the last argument of a C-variadic function
@@ -33,12 +33,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {}
3333

3434
const extern "C" fn f4_2(x: isize, ...) {}
3535
//~^ ERROR functions cannot be both `const` and C-variadic
36-
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
36+
//~| ERROR functions with a C variable argument list must be unsafe
3737
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
3838

3939
const extern "C" fn f4_3(..., x: isize, ...) {}
4040
//~^ ERROR functions cannot be both `const` and C-variadic
41-
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
41+
//~| ERROR functions with a C variable argument list must be unsafe
4242
//~| ERROR `...` must be the last argument of a C-variadic function
4343

4444
extern "C" {

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

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,55 @@ error: `...` is not supported for non-extern functions
1010
LL | fn f1_2(...) {}
1111
| ^^^
1212

13-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
13+
error: functions with a C variable argument list must be unsafe
1414
--> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
1515
|
1616
LL | extern "C" fn f2_1(x: isize, ...) {}
1717
| ^^^
18+
|
19+
help: add the `unsafe` keyword to this definition
20+
|
21+
LL | unsafe extern "C" fn f2_1(x: isize, ...) {}
22+
| ++++++
1823

19-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
24+
error: functions with a C variable argument list must be unsafe
2025
--> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
2126
|
2227
LL | extern "C" fn f2_2(...) {}
2328
| ^^^
29+
|
30+
help: add the `unsafe` keyword to this definition
31+
|
32+
LL | unsafe extern "C" fn f2_2(...) {}
33+
| ++++++
2434

2535
error: `...` must be the last argument of a C-variadic function
2636
--> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
2737
|
2838
LL | extern "C" fn f2_3(..., x: isize) {}
2939
| ^^^
3040

31-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
41+
error: functions with a C variable argument list must be unsafe
3242
--> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
3343
|
3444
LL | extern "C" fn f3_1(x: isize, ...) {}
3545
| ^^^
46+
|
47+
help: add the `unsafe` keyword to this definition
48+
|
49+
LL | unsafe extern "C" fn f3_1(x: isize, ...) {}
50+
| ++++++
3651

37-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
52+
error: functions with a C variable argument list must be unsafe
3853
--> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
3954
|
4055
LL | extern "C" fn f3_2(...) {}
4156
| ^^^
57+
|
58+
help: add the `unsafe` keyword to this definition
59+
|
60+
LL | unsafe extern "C" fn f3_2(...) {}
61+
| ++++++
4262

4363
error: `...` must be the last argument of a C-variadic function
4464
--> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
@@ -58,11 +78,16 @@ error: functions cannot be both `const` and C-variadic
5878
LL | const extern "C" fn f4_2(x: isize, ...) {}
5979
| ^^^^^ `const` because of this ^^^ C-variadic because of this
6080

61-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
81+
error: functions with a C variable argument list must be unsafe
6282
--> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
6383
|
6484
LL | const extern "C" fn f4_2(x: isize, ...) {}
6585
| ^^^
86+
|
87+
help: add the `unsafe` keyword to this definition
88+
|
89+
LL | constunsafe extern "C" fn f4_2(x: isize, ...) {}
90+
| ++++++
6691

6792
error: `...` must be the last argument of a C-variadic function
6893
--> $DIR/variadic-ffi-semantic-restrictions.rs:39:26
@@ -76,11 +101,16 @@ error: functions cannot be both `const` and C-variadic
76101
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
77102
| ^^^^^ `const` because of this ^^^ C-variadic because of this
78103

79-
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
104+
error: functions with a C variable argument list must be unsafe
80105
--> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
81106
|
82107
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
83108
| ^^^
109+
|
110+
help: add the `unsafe` keyword to this definition
111+
|
112+
LL | constunsafe extern "C" fn f4_3(..., x: isize, ...) {}
113+
| ++++++
84114

85115
error: `...` must be the last argument of a C-variadic function
86116
--> $DIR/variadic-ffi-semantic-restrictions.rs:45:13

0 commit comments

Comments
 (0)