feature-gate c-variadic definitions and calls in const contexts

This commit is contained in:
Folkert de Vries 2026-01-28 21:03:41 +01:00
parent f5bf3353e6
commit 981dacc34f
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
11 changed files with 88 additions and 5 deletions

View file

@ -698,6 +698,13 @@ impl<'a> AstValidator<'a> {
unreachable!("C variable argument list cannot be used in closures")
};
if let Const::Yes(_) = sig.header.constness
&& !self.features.enabled(sym::const_c_variadic)
{
let msg = format!("c-variadic const function definitions are unstable");
feature_err(&self.sess, sym::const_c_variadic, sig.span, msg).emit();
}
if let Some(coroutine_kind) = sig.header.coroutine_kind {
self.dcx().emit_err(errors::CoroutineAndCVariadic {
spans: vec![coroutine_kind.span(), variadic_param.span],

View file

@ -815,6 +815,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
});
}
if self.tcx.fn_sig(callee).skip_binder().c_variadic() {
self.check_op(ops::FnCallCVariadic)
}
// At this point, we are calling a function, `callee`, whose `DefId` is known...
// `begin_panic` and `panic_display` functions accept generic

View file

@ -75,6 +75,27 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
}
}
/// A c-variadic function call.
#[derive(Debug)]
pub(crate) struct FnCallCVariadic;
impl<'tcx> NonConstOp<'tcx> for FnCallCVariadic {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable {
gate: sym::const_c_variadic,
gate_already_checked: false,
safe_to_expose_on_stable: false,
is_function_call: true,
}
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.tcx.sess.create_feature_err(
errors::NonConstCVariadicCall { span, kind: ccx.const_kind() },
sym::const_c_variadic,
)
}
}
/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
#[derive(Debug)]
pub(crate) struct ConditionallyConstCall<'tcx> {

View file

@ -531,6 +531,19 @@ pub struct NonConstClosure {
pub non_or_conditionally: &'static str,
}
#[derive(Diagnostic)]
#[diag(r#"calling const c-variadic functions is unstable in {$kind ->
[const] constant
[static] static
[const_fn] constant function
*[other] {""}
}s"#, code = E0015)]
pub struct NonConstCVariadicCall {
#[primary_span]
pub span: Span,
pub kind: ConstContext,
}
#[derive(Subdiagnostic)]
pub enum NonConstClosureNote {
#[note("function defined here, but it is not `const`")]

View file

@ -420,6 +420,8 @@ declare_features! (
(unstable, const_async_blocks, "1.53.0", Some(85368)),
/// Allows `const { ... }` as a shorthand for `const _: () = const { ... };` for module items.
(unstable, const_block_items, "CURRENT_RUSTC_VERSION", Some(149226)),
/// Allows defining and calling c-variadic functions in const contexts.
(unstable, const_c_variadic, "CURRENT_RUSTC_VERSION", Some(151787)),
/// Allows `const || {}` closures in const contexts.
(incomplete, const_closures, "1.68.0", Some(106003)),
/// Allows using `[const] Destruct` bounds and calling drop impls in const contexts.

View file

@ -740,6 +740,7 @@ symbols! {
const_allocate,
const_async_blocks,
const_block_items,
const_c_variadic,
const_closures,
const_compare_raw_pointers,
const_constructor,

View file

@ -205,7 +205,7 @@ impl VaList<'_> {
}
}
#[rustc_const_unstable(feature = "c_variadic_const", issue = "none")]
#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
impl<'f> const Clone for VaList<'f> {
#[inline]
fn clone(&self) -> Self {
@ -217,7 +217,7 @@ impl<'f> const Clone for VaList<'f> {
}
}
#[rustc_const_unstable(feature = "c_variadic_const", issue = "none")]
#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
impl<'f> const Drop for VaList<'f> {
fn drop(&mut self) {
// SAFETY: this variable argument list is being dropped, so won't be read from again.
@ -293,7 +293,7 @@ impl<'f> VaList<'f> {
///
/// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html
#[inline]
#[rustc_const_unstable(feature = "c_variadic_const", issue = "none")]
#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
pub const unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
// SAFETY: the caller must uphold the safety contract for `va_arg`.
unsafe { va_arg(self) }

View file

@ -1,7 +1,7 @@
//@ build-fail
#![feature(c_variadic)]
#![feature(c_variadic_const)]
#![feature(const_c_variadic)]
#![feature(const_trait_impl)]
#![feature(const_destruct)]
#![feature(const_clone)]

View file

@ -3,8 +3,8 @@
//@ ignore-backends: gcc
#![feature(c_variadic)]
#![feature(const_c_variadic)]
#![feature(const_destruct)]
#![feature(c_variadic_const)]
#![feature(const_cmp)]
#![feature(const_trait_impl)]

View file

@ -0,0 +1,11 @@
#![feature(c_variadic)]
fn main() {
const unsafe extern "C" fn foo(ap: ...) {
//~^ ERROR c-variadic const function definitions are unstable
core::mem::forget(ap);
}
const { unsafe { foo() } }
//~^ ERROR calling const c-variadic functions is unstable in constants
}

View file

@ -0,0 +1,24 @@
error[E0658]: c-variadic const function definitions are unstable
--> $DIR/feature-gate-const-c-variadic.rs:4:5
|
LL | const unsafe extern "C" fn foo(ap: ...) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #151787 <https://github.com/rust-lang/rust/issues/151787> for more information
= help: add `#![feature(const_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[E0015]: calling const c-variadic functions is unstable in constants
--> $DIR/feature-gate-const-c-variadic.rs:9:22
|
LL | const { unsafe { foo() } }
| ^^^^^
|
= note: see issue #151787 <https://github.com/rust-lang/rust/issues/151787> for more information
= help: add `#![feature(const_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 2 previous errors
Some errors have detailed explanations: E0015, E0658.
For more information about an error, try `rustc --explain E0015`.