diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f9a64ffe09c4..ac2ba6b2b92a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -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], diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 57396b657a3f..4ce0345f2e61 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -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 diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 5b62ba8c1605..be8f0f430e13 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -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> { diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 061ed38c9df1..886995aa3a40 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -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`")] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 082558cf9a93..36be4a037806 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -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. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b9a9d8029d28..a39f01c8e70b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -740,6 +740,7 @@ symbols! { const_allocate, const_async_blocks, const_block_items, + const_c_variadic, const_closures, const_compare_raw_pointers, const_constructor, diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 45a9b7ba5293..4ed93f54d43c 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -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(&mut self) -> T { // SAFETY: the caller must uphold the safety contract for `va_arg`. unsafe { va_arg(self) } diff --git a/tests/ui/consts/const-eval/c-variadic-fail.rs b/tests/ui/consts/const-eval/c-variadic-fail.rs index 859dfed35719..b5a400a8bf25 100644 --- a/tests/ui/consts/const-eval/c-variadic-fail.rs +++ b/tests/ui/consts/const-eval/c-variadic-fail.rs @@ -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)] diff --git a/tests/ui/consts/const-eval/c-variadic.rs b/tests/ui/consts/const-eval/c-variadic.rs index ec49b5cc5831..2f8d043fb5db 100644 --- a/tests/ui/consts/const-eval/c-variadic.rs +++ b/tests/ui/consts/const-eval/c-variadic.rs @@ -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)] diff --git a/tests/ui/feature-gates/feature-gate-const-c-variadic.rs b/tests/ui/feature-gates/feature-gate-const-c-variadic.rs new file mode 100644 index 000000000000..4e8b3c54b1fd --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-c-variadic.rs @@ -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 +} diff --git a/tests/ui/feature-gates/feature-gate-const-c-variadic.stderr b/tests/ui/feature-gates/feature-gate-const-c-variadic.stderr new file mode 100644 index 000000000000..8fd85be08fca --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-const-c-variadic.stderr @@ -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 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 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`.