diff options
| author | Folkert de Vries <folkert@folkertdev.nl> | 2025-09-08 18:45:41 +0200 |
|---|---|---|
| committer | Folkert de Vries <folkert@folkertdev.nl> | 2025-09-09 21:30:38 +0200 |
| commit | 0c96200f268df10d4f3ac102f3161c67e5e67221 (patch) | |
| tree | bfb8cc16075c6a8f1e8a0e53368fae4d2b89c4bb | |
| parent | 5de9bc73e76f60ee27c37f20d0a9530e5a957df7 (diff) | |
| download | rust-0c96200f268df10d4f3ac102f3161c67e5e67221.tar.gz rust-0c96200f268df10d4f3ac102f3161c67e5e67221.zip | |
c-variadic: reject non-unsafe functions
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/messages.ftl | 4 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_ast_passes/src/errors.rs | 15 | ||||
| -rw-r--r-- | tests/ui/parser/variadic-ffi-semantic-restrictions.rs | 12 | ||||
| -rw-r--r-- | tests/ui/parser/variadic-ffi-semantic-restrictions.stderr | 42 |
6 files changed, 98 insertions, 21 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 2733a2603d6..915bae9e5f5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2309,6 +2309,22 @@ impl FnSig { self.span.shrink_to_lo() } + + /// The span of the header's safety, or where to insert it if empty. + pub fn safety_span(&self) -> Span { + match self.header.safety { + Safety::Unsafe(span) | Safety::Safe(span) => span, + Safety::Default => { + // Insert after the `coroutine_kind` if available. + if let Some(extern_span) = self.header.ext.span() { + return extern_span.shrink_to_lo(); + } + + // Insert right at the front of the signature. + self.header_span().shrink_to_hi() + } + } + } } /// A constraint on an associated item. @@ -3553,6 +3569,13 @@ impl Extern { None => Extern::Implicit(span), } } + + pub fn span(self) -> Option<Span> { + match self { + Extern::None => None, + Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), + } + } } /// A function header. diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 958797a6089..1aa38a1beda 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -68,6 +68,10 @@ 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_must_be_unsafe = + functions with a C variable argument list must be unsafe + .suggestion = add the `unsafe` keyword to this definition + ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f425acda358..7b32778ddf0 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -698,20 +698,25 @@ impl<'a> AstValidator<'a> { FnCtxt::Foreign => return, FnCtxt::Free => match sig.header.ext { Extern::Implicit(_) => { - if matches!(sig.header.safety, Safety::Unsafe(_)) { - return; + // Implicitly defaults to C. + if !matches!(sig.header.safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + span: variadic_param.span, + unsafe_span: sig.safety_span(), + }); } - - self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span }); } Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => { - if matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) { - if matches!(sig.header.safety, Safety::Unsafe(_)) { - return; - } + if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) { + self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span }); } - self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.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 }; diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 6b57e5ef376..946a22d2e75 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -333,6 +333,21 @@ pub(crate) struct CVariadicNoExtern { } #[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_must_be_unsafe)] +pub(crate) struct CVariadicMustBeUnsafe { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_bad_c_variadic)] pub(crate) struct BadCVariadic { #[primary_span] diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index fe5421ab2c0..ff491322efc 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -10,19 +10,19 @@ fn f1_2(...) {} //~^ ERROR `...` is not supported for non-extern functions extern "C" fn f2_1(x: isize, ...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f2_2(...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f2_3(..., x: isize) {} //~^ ERROR `...` must be the last argument of a C-variadic function extern "C" fn f3_1(x: isize, ...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f3_2(...) {} -//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~^ ERROR functions with a C variable argument list must be unsafe extern "C" fn f3_3(..., x: isize) {} //~^ ERROR `...` must be the last argument of a C-variadic function @@ -33,12 +33,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {} const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~| ERROR functions with a C variable argument list must be unsafe //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(..., x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +//~| ERROR functions with a C variable argument list must be unsafe //~| ERROR `...` must be the last argument of a C-variadic function extern "C" { diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index 0abe1526405..98f1d79f8f4 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -10,17 +10,27 @@ error: `...` is not supported for non-extern functions LL | fn f1_2(...) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f2_1(x: isize, ...) {} + | ++++++ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f2_2(...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 @@ -28,17 +38,27 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:21:30 | LL | extern "C" fn f3_1(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f3_1(x: isize, ...) {} + | ++++++ -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:24:20 | LL | extern "C" fn f3_2(...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "C" fn f3_2(...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:27:20 @@ -58,11 +78,16 @@ error: functions cannot be both `const` and C-variadic LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:34:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | const unsafe extern "C" fn f4_2(x: isize, ...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:39:26 @@ -76,11 +101,16 @@ error: functions cannot be both `const` and C-variadic LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +error: functions with a C variable argument list must be unsafe --> $DIR/variadic-ffi-semantic-restrictions.rs:39:41 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | const unsafe extern "C" fn f4_3(..., x: isize, ...) {} + | ++++++ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:45:13 |
