Skip to content

Commit

Permalink
Explicitly reject const C-variadic functions
Browse files Browse the repository at this point in the history
Trying to use C-variadics in a const function would previously fail with
an error like "destructor of `VaListImpl<'_>` cannot be evaluated at
compile-time".

Add an explicit check for const C-variadics to provide a clearer error:
"functions cannot be both `const` and C-variadic".
  • Loading branch information
nicholasbishop committed Oct 29, 2023
1 parent 690b017 commit c88bb2a
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 22 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ ast_passes_const_and_async = functions cannot be both `const` and `async`
.async = `async` because of this
.label = {""}
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
.const = `const` because of this
.variadic = C-variadic because of this
ast_passes_const_without_body =
free constant item without body
.suggestion = provide a definition for the constant
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,11 @@ impl<'a> AstValidator<'a> {
}
}

/// Reject C-variadic type unless the function is foreign,
/// or free and `unsafe extern "C"` semantically.
/// Reject invalid C-variadic types.
///
/// C-variadics must be:
/// - Non-const
/// - Either foreign, or free and `unsafe extern "C"` semantically
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
let Some(variadic_span) = fk
.decl()
Expand All @@ -495,6 +498,16 @@ impl<'a> AstValidator<'a> {
return;
};

if let Some(header) = fk.header() {
if let Const::Yes(const_span) = header.constness {
self.err_handler().emit_err(errors::ConstAndCVariadic {
spans: vec![const_span, variadic_span],
const_span,
variadic_span,
});
}
}

match (fk.ctxt(), fk.header()) {
(Some(FnCtxt::Foreign), _) => return,
(Some(FnCtxt::Free), Some(header)) => match header.ext {
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,17 @@ pub struct ConstAndAsync {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_const_and_c_variadic)]
pub struct ConstAndCVariadic {
#[primary_span]
pub spans: Vec<Span>,
#[label(ast_passes_const)]
pub const_span: Span,
#[label(ast_passes_variadic)]
pub variadic_span: Span,
}

#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = "E0130")]
pub struct PatternInForeign {
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/parser/variadic-ffi-semantic-restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,18 @@ extern "C" fn f3_3(..., x: isize) {}
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function

const unsafe extern "C" fn f4_1(x: isize, ...) {}
//~^ ERROR functions cannot be both `const` and C-variadic

const extern "C" fn f4_2(x: isize, ...) {}
//~^ ERROR functions cannot be both `const` and C-variadic
//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic

const extern "C" fn f4_3(..., x: isize, ...) {}
//~^ ERROR functions cannot be both `const` and C-variadic
//~| ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function

extern "C" {
fn e_f1(...);
//~^ ERROR C-variadic function must be declared with at least one named argument
Expand All @@ -53,6 +65,9 @@ impl X {
fn i_f4(..., x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR `...` must be the last argument of a C-variadic function
const fn i_f5(x: isize, ...) {}
//~^ ERROR only foreign or `unsafe extern "C"` functions may be C-variadic
//~| ERROR functions cannot be both `const` and C-variadic
}

trait T {
Expand Down
92 changes: 72 additions & 20 deletions tests/ui/parser/variadic-ffi-semantic-restrictions.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -76,119 +76,171 @@ error: only foreign or `unsafe extern "C"` functions may be C-variadic
LL | extern "C" fn f3_3(..., x: isize) {}
| ^^^

error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:35:1
|
LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
| ^^^^^ `const` because of this ^^^ C-variadic because of this

error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:38:1
|
LL | const extern "C" fn f4_2(x: isize, ...) {}
| ^^^^^ `const` because of this ^^^ C-variadic because of this

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:38:36
|
LL | const extern "C" fn f4_2(x: isize, ...) {}
| ^^^

error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:26
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^

error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:1
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^^^ ^^^ C-variadic because of this
| |
| `const` because of this

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:26
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^

error: C-variadic function must be declared with at least one named argument
--> $DIR/variadic-ffi-semantic-restrictions.rs:36:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:48:13
|
LL | fn e_f1(...);
| ^^^

error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:38:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:50:13
|
LL | fn e_f2(..., x: isize);
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:45:23
--> $DIR/variadic-ffi-semantic-restrictions.rs:57:23
|
LL | fn i_f1(x: isize, ...) {}
| ^^^

error: C-variadic function must be declared with at least one named argument
--> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
|
LL | fn i_f2(...) {}
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:47:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
|
LL | fn i_f2(...) {}
| ^^^

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

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:50:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:13
|
LL | fn i_f3(..., x: isize, ...) {}
| ^^^

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

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:13
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^

error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:68:5
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^^^ ^^^ C-variadic because of this
| |
| `const` because of this

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:68:29
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:23
--> $DIR/variadic-ffi-semantic-restrictions.rs:74:23
|
LL | fn t_f1(x: isize, ...) {}
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:61:23
--> $DIR/variadic-ffi-semantic-restrictions.rs:76:23
|
LL | fn t_f2(x: isize, ...);
| ^^^

error: C-variadic function must be declared with at least one named argument
--> $DIR/variadic-ffi-semantic-restrictions.rs:63:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:78:13
|
LL | fn t_f3(...) {}
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:63:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:78:13
|
LL | fn t_f3(...) {}
| ^^^

error: C-variadic function must be declared with at least one named argument
--> $DIR/variadic-ffi-semantic-restrictions.rs:66:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:81:13
|
LL | fn t_f4(...);
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:66:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:81:13
|
LL | fn t_f4(...);
| ^^^

error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:69:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:84:13
|
LL | fn t_f5(..., x: isize) {}
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:69:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:84:13
|
LL | fn t_f5(..., x: isize) {}
| ^^^

error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:72:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:87:13
|
LL | fn t_f6(..., x: isize);
| ^^^

error: only foreign or `unsafe extern "C"` functions may be C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:72:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:87:13
|
LL | fn t_f6(..., x: isize);
| ^^^

error: aborting due to 32 previous errors
error: aborting due to 40 previous errors

0 comments on commit c88bb2a

Please sign in to comment.