diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bde63fd501aa2..271c4dc352e88 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -503,7 +503,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let va_list_arg_idx = self.fn_abi.args.len(); match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { LocalRef::Place(va_list) => { - bx.va_end(va_list.val.llval); + if super::is_va_list_struct_on_stack(bx) { + // Call `va_end` on the `&mut VaListTag` that is stored in `va_list`. + let inner_field = va_list.project_field(bx, 0); + + let tag_ptr = bx.load( + bx.backend_type(inner_field.layout), + inner_field.val.llval, + inner_field.layout.align.abi, + ); + + bx.va_end(tag_ptr); + } else { + // Call `va_end` on the `VaListTag` that is stored in `va_list`. + let tag_ptr = va_list.project_field(bx, 0); + bx.va_end(tag_ptr.val.llval); + } } _ => bug!("C-variadic function must have a `VaList` place"), } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 10b44a1faf087..f79256ec99f1a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -1,5 +1,7 @@ use std::iter; +use rustc_ast::Mutability; +use rustc_hir as hir; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -371,6 +373,41 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( mir } +/// Whether on this target, the `VaList` is a reference to a struct on the stack. +/// +/// If this function returns `true`, the `core` crate defines a `VaListTag` struct +/// matching the varargs ABI for this target. +/// +/// In other cases, the `VaList` is an opaque pointer. Generally this is just a pointer to the +/// caller's stack where the variadic arguments are stored sequentially. +fn is_va_list_struct_on_stack<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> bool { + let did = bx.tcx().require_lang_item(hir::LangItem::VaList, rustc_span::Span::default()); + let ty = bx.tcx().type_of(did).instantiate_identity(); + + // Check how `VaList` is implemented for the current target. It can be either: + // + // - a reference to a value on the stack + // - a struct wrapping a pointer + let Some(adt_def) = ty.ty_adt_def() else { bug!("invalid `VaList`") }; + let variant = adt_def.non_enum_variant(); + + if variant.fields.len() != 1 { + bug!("`VaList` must have exactly 1 field") + } + let field = variant.fields.iter().next().unwrap(); + let field_ty = bx.tcx().type_of(field.did).instantiate_identity(); + + if field_ty.is_adt() { + return false; + } + + if let Some(Mutability::Mut) = field_ty.ref_mutability() { + return true; + } + + bug!("invalid `VaList` field type") +} + /// Produces, for each argument, a `Value` pointing at the /// argument's value. As arguments are places, these are always /// indirect. @@ -437,10 +474,35 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() { - let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); - bx.va_start(va_list.val.llval); + use rustc_hir::LangItem; + + let va_list_tag_ty = { + let did = + bx.tcx().require_lang_item(LangItem::VaListTag, arg_decl.source_info.span); + let ty = bx.tcx().type_of(did).instantiate_identity(); + bx.tcx().normalize_erasing_regions(fx.cx.typing_env(), ty) + }; + let va_list_tag_layout = bx.layout_of(va_list_tag_ty); + + // Construct the `VaListTag` on the stack. + let va_list_tag = PlaceRef::alloca(bx, va_list_tag_layout); + + // Initialize the alloca. + bx.va_start(va_list_tag.val.llval); + + let va_list_tag = if is_va_list_struct_on_stack(bx) { + va_list_tag.val.llval + } else { + bx.load( + bx.backend_type(va_list_tag_layout), + va_list_tag.val.llval, + va_list_tag.layout.align.abi, + ) + }; - return LocalRef::Place(va_list); + let tmp = PlaceRef::alloca(bx, bx.layout_of(arg_ty)); + bx.store_to_place(va_list_tag, tmp.val); + return LocalRef::Place(tmp); } let arg = &fx.fn_abi.args[idx]; diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 10dd5ff9aa76a..c1abd47137bc2 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -230,6 +230,7 @@ language_item_table! { UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None; VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None; + VaListTag, sym::va_list_tag, va_list_tag, Target::Struct, GenericRequirement::None; Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0); DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index cebf7d1b5324e..f3dca686c8d46 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -175,8 +175,8 @@ pub(crate) fn check_intrinsic_type( ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon), ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); - let mk_va_list_ty = |mutbl| { - let did = tcx.require_lang_item(LangItem::VaList, span); + let mk_va_list_tag_ty = |mutbl| { + let did = tcx.require_lang_item(LangItem::VaListTag, span); let region = ty::Region::new_bound( tcx, ty::INNERMOST, @@ -507,16 +507,16 @@ pub(crate) fn check_intrinsic_type( } sym::va_start | sym::va_end => { - (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit) + (0, 0, vec![mk_va_list_tag_ty(hir::Mutability::Mut).0], tcx.types.unit) } sym::va_copy => { - let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not); + let (va_list_ref_ty, va_list_ty) = mk_va_list_tag_ty(hir::Mutability::Not); let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty); (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit) } - sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)), + sym::va_arg => (1, 0, vec![mk_va_list_tag_ty(hir::Mutability::Mut).0], param(0)), sym::nontemporal_store => { (1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 01d474095a739..64bf997747f69 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2312,6 +2312,7 @@ symbols! { va_copy, va_end, va_list, + va_list_tag, va_start, val, validity, diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 0bc98e2ea8645..371761a094818 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -28,7 +28,7 @@ pub mod c_str; issue = "44930", reason = "the `c_variadic` feature has not been properly tested on all supported platforms" )] -pub use self::va_list::{VaArgSafe, VaList, VaListImpl}; +pub use self::va_list::{VaArgSafe, VaList, VaListTag, va_copy}; #[unstable( feature = "c_variadic", diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 8f7c090bc1ba2..48e01381d4c61 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -3,12 +3,10 @@ //! Better known as "varargs". use crate::ffi::c_void; -#[allow(unused_imports)] -use crate::fmt; -use crate::marker::{PhantomData, PhantomInvariantLifetime}; -use crate::ops::{Deref, DerefMut}; +use crate::marker::PhantomInvariantLifetime; +use crate::mem::MaybeUninit; -// The name is WIP, using `VaListImpl` for now. +// The name is WIP, using `VaListTag` for now. // // Most targets explicitly specify the layout of `va_list`, this layout is matched here. crate::cfg_select! { @@ -23,68 +21,78 @@ crate::cfg_select! { /// /// [AArch64 Procedure Call Standard]: /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[doc(hidden)] + #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { stack: *mut c_void, gr_top: *mut c_void, vr_top: *mut c_void, gr_offs: i32, vr_offs: i32, - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } } all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => { /// PowerPC ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[doc(hidden)] + #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { gpr: u8, fpr: u8, reserved: u16, overflow_arg_area: *mut c_void, reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } } target_arch = "s390x" => { /// s390x ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[doc(hidden)] + #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { gpr: i64, fpr: i64, overflow_arg_area: *mut c_void, reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } } all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => { /// x86_64 ABI implementation of a `va_list`. - #[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 + #[doc(hidden)] + #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { gp_offset: i32, fp_offset: i32, overflow_arg_area: *mut c_void, reg_save_area: *mut c_void, - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } } target_arch = "xtensa" => { /// Xtensa ABI implementation of a `va_list`. + #[doc(hidden)] #[repr(C)] #[derive(Debug)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { stk: *mut i32, reg: *mut i32, ndx: i32, - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } } @@ -93,24 +101,23 @@ crate::cfg_select! { // - apple aarch64 (see https://github.com/rust-lang/rust/pull/56599) // - windows // - uefi - // - any other target for which we don't specify the `VaListImpl` above + // - any other target for which we don't specify the `VaListTag` above // // In this implementation the `va_list` type is just an alias for an opaque pointer. // That pointer is probably just the next variadic argument on the caller's stack. _ => { /// Basic implementation of a `va_list`. + #[doc(hidden)] #[repr(transparent)] - #[lang = "va_list"] - pub struct VaListImpl<'f> { + #[lang = "va_list_tag"] + #[unstable(feature = "va_list_impl", issue = "none")] + pub struct VaListTag<'a> { ptr: *mut c_void, - - // Invariant over `'f`, so each `VaListImpl<'f>` object is tied to - // the region of the function it's defined in - _marker: PhantomInvariantLifetime<'f>, + _marker: PhantomInvariantLifetime<'a>, } - impl<'f> fmt::Debug for VaListImpl<'f> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + impl<'a> crate::fmt::Debug for VaListTag<'a> { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { write!(f, "va_list* {:p}", self.ptr) } } @@ -134,53 +141,98 @@ crate::cfg_select! { /// A wrapper for a `va_list` #[repr(transparent)] #[derive(Debug)] - pub struct VaList<'a, 'f: 'a> { - inner: &'a mut VaListImpl<'f>, - _marker: PhantomData<&'a mut VaListImpl<'f>>, + #[lang = "va_list"] + pub struct VaList<'a> { + inner: &'a mut VaListTag<'a>, } + impl<'a> VaList<'a> { + #[doc(hidden)] + #[unstable(feature = "va_list_impl", issue = "none")] + #[inline(always)] + pub fn copy<'b>(&self, tag: &'b mut MaybeUninit>) -> VaList<'b> + where + 'a: 'b, + { + // The signature of `copy` already enforces the correct lifetime constraints. + // `va_copy` is an intrinsic, which makes it less flexible lifetime-wise. + let ptr = tag.as_mut_ptr().cast::>(); + + // SAFETY: `tag` has sufficient space to store a `VaListTag`. + unsafe { va_copy_intrinsic::va_copy(ptr, &self.inner) }; - impl<'f> VaListImpl<'f> { - /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: self, _marker: PhantomData } + // SAFETY: `va_copy` has initialized the tag. + VaList { inner: unsafe { tag.assume_init_mut() } } } } + } _ => { /// A wrapper for a `va_list` #[repr(transparent)] #[derive(Debug)] - pub struct VaList<'a, 'f: 'a> { - inner: VaListImpl<'f>, - _marker: PhantomData<&'a mut VaListImpl<'f>>, + #[lang = "va_list"] + pub struct VaList<'a> { + inner: VaListTag<'a>, } - impl<'f> VaListImpl<'f> { - /// Converts a [`VaListImpl`] into a [`VaList`] that is binary-compatible with C's `va_list`. - #[inline] - pub fn as_va_list<'a>(&'a mut self) -> VaList<'a, 'f> { - VaList { inner: VaListImpl { ..*self }, _marker: PhantomData } + + impl<'a> VaList<'a> { + #[doc(hidden)] + #[unstable(feature = "va_list_impl", issue = "none")] + #[inline(always)] + pub fn copy<'b>(&self, tag: &'b mut MaybeUninit>) -> VaList<'b> + where + 'a: 'b, + { + // The signature of `copy` already enforces the correct lifetime constraints. + // `va_copy` is an intrinsic, which makes it less flexible lifetime-wise. + let ptr = tag.as_mut_ptr().cast::>(); + + // SAFETY: `tag` has sufficient space to store a `VaListTag`. + unsafe { va_copy_intrinsic::va_copy(ptr, &self.inner) }; + + // SAFETY: `va_copy` has initialized the tag. + VaList { inner: unsafe { tag.assume_init_read() } } } } } } -impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { - type Target = VaListImpl<'f>; +/// Copy a [`VaList`]. +#[allow_internal_unstable(super_let)] +#[allow_internal_unstable(va_list_impl)] +pub macro va_copy($va_list:expr $(,)?) {{ + super let mut tag = $crate::mem::MaybeUninit::uninit(); + $va_list.copy(&mut tag) +}} - #[inline] - fn deref(&self) -> &VaListImpl<'f> { - &self.inner +impl<'a> VaListTag<'a> { + /// Advance to the next arg. + #[inline(never)] + unsafe fn arg(&mut self) -> T { + // SAFETY: the caller must uphold the safety contract for `va_arg`. + unsafe { va_arg(self) } } } -impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { +impl<'a> VaList<'a> { + /// Advance to the next arg. #[inline] - fn deref_mut(&mut self) -> &mut VaListImpl<'f> { - &mut self.inner + pub unsafe fn arg(&mut self) -> T { + // SAFETY: the caller must uphold the safety contract for `va_arg`. + unsafe { self.inner.arg() } + } + + /// Copies the `va_list` at the current location. + pub unsafe fn with_copy(&self, f: F) -> R + where + F: FnOnce(VaList<'_>) -> R, + { + let ap = va_copy!(self); + let ret = f(ap); + ret } } @@ -201,7 +253,7 @@ mod sealed { impl Sealed for *const T {} } -/// Trait which permits the allowed types to be used with [`VaListImpl::arg`]. +/// Trait which permits the allowed types to be used with [`VaList::arg`]. /// /// # Safety /// @@ -231,42 +283,7 @@ unsafe impl VaArgSafe for f64 {} unsafe impl VaArgSafe for *mut T {} unsafe impl VaArgSafe for *const T {} -impl<'f> VaListImpl<'f> { - /// Advance to the next arg. - #[inline] - pub unsafe fn arg(&mut self) -> T { - // SAFETY: the caller must uphold the safety contract for `va_arg`. - unsafe { va_arg(self) } - } - - /// Copies the `va_list` at the current location. - pub unsafe fn with_copy(&self, f: F) -> R - where - F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R, - { - let mut ap = self.clone(); - let ret = f(ap.as_va_list()); - // SAFETY: the caller must uphold the safety contract for `va_end`. - unsafe { - va_end(&mut ap); - } - ret - } -} - -impl<'f> Clone for VaListImpl<'f> { - #[inline] - fn clone(&self) -> Self { - let mut dest = crate::mem::MaybeUninit::uninit(); - // SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal - unsafe { - va_copy(dest.as_mut_ptr(), self); - dest.assume_init() - } - } -} - -impl<'f> Drop for VaListImpl<'f> { +impl Drop for VaListTag<'_> { fn drop(&mut self) { // FIXME: this should call `va_end`, but there's no clean way to // guarantee that `drop` always gets inlined into its caller, @@ -285,15 +302,20 @@ impl<'f> Drop for VaListImpl<'f> { /// `va_copy`. #[rustc_intrinsic] #[rustc_nounwind] -unsafe fn va_end(ap: &mut VaListImpl<'_>); +#[allow(unused)] +unsafe fn va_end(ap: &mut VaListTag<'_>); -/// Copies the current location of arglist `src` to the arglist `dst`. -#[rustc_intrinsic] -#[rustc_nounwind] -unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); +// This intrinsic is in a module so that its name does not clash with the `va_copy!` macro. +mod va_copy_intrinsic { + use super::VaListTag; + /// Copies the current location of arglist `src` to the arglist `dst`. + #[rustc_intrinsic] + #[rustc_nounwind] + pub(super) unsafe fn va_copy<'a>(dest: *mut VaListTag<'a>, src: &VaListTag<'a>); +} /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. #[rustc_intrinsic] #[rustc_nounwind] -unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; +unsafe fn va_arg(ap: &mut VaListTag<'_>) -> T; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6e160eddecb97..653f0fe799d8e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -177,6 +177,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] +#![feature(super_let)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index f44e12d48addf..0fa9c5cde30e6 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -172,7 +172,7 @@ pub use core::ffi::c_void; all supported platforms", issue = "44930" )] -pub use core::ffi::{VaArgSafe, VaList, VaListImpl}; +pub use core::ffi::{VaArgSafe, VaList, VaListTag, va_copy}; #[stable(feature = "core_ffi_c", since = "1.64.0")] pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, diff --git a/tests/codegen/cffi/c-variadic-copy.rs b/tests/codegen/cffi/c-variadic-copy.rs index 4c61c4fcf68d3..4601cfddcd7d8 100644 --- a/tests/codegen/cffi/c-variadic-copy.rs +++ b/tests/codegen/cffi/c-variadic-copy.rs @@ -3,14 +3,14 @@ #![crate_type = "lib"] #![feature(c_variadic)] #![no_std] -use core::ffi::VaList; +use core::ffi::{VaList, va_copy}; extern "C" { fn foreign_c_variadic_1(_: VaList, ...); } pub unsafe extern "C" fn clone_variadic(ap: VaList) { - let mut ap2 = ap.clone(); + let mut ap2 = va_copy!(ap); // CHECK: call void @llvm.va_copy - foreign_c_variadic_1(ap2.as_va_list(), 42i32); + foreign_c_variadic_1(ap2, 42i32); } diff --git a/tests/codegen/cffi/c-variadic-opt.rs b/tests/codegen/cffi/c-variadic-opt.rs index 7e544ee7f37da..cb4c246b40a1f 100644 --- a/tests/codegen/cffi/c-variadic-opt.rs +++ b/tests/codegen/cffi/c-variadic-opt.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] #![feature(c_variadic)] #![no_std] -use core::ffi::VaList; +use core::ffi::{VaList, va_copy}; extern "C" { fn vprintf(fmt: *const i8, ap: VaList) -> i32; @@ -12,19 +12,19 @@ extern "C" { // Ensure that `va_start` and `va_end` are properly injected even // when the "spoofed" `VaListImpl` is not used. #[no_mangle] -pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { +pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, ap: ...) -> i32 { // CHECK: call void @llvm.va_start - vprintf(fmt, ap.as_va_list()) + vprintf(fmt, ap) // CHECK: call void @llvm.va_end } -// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy` +// Check that `va_copy!` gets inlined into a direct call to `llvm.va_copy` #[no_mangle] -pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 { +pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, ap: ...) -> i32 { // CHECK: call void @llvm.va_start - let mut ap2 = ap.clone(); + let ap2 = va_copy!(ap); // CHECK: call void @llvm.va_copy - let res = vprintf(fmt, ap2.as_va_list()); + let res = vprintf(fmt, ap2); res // CHECK: call void @llvm.va_end } diff --git a/tests/ui/abi/variadic-ffi.rs b/tests/ui/abi/variadic-ffi.rs index 6cfae0f2a320f..5ed04eb72caf6 100644 --- a/tests/ui/abi/variadic-ffi.rs +++ b/tests/ui/abi/variadic-ffi.rs @@ -1,7 +1,7 @@ //@ run-pass #![feature(c_variadic)] -use std::ffi::VaList; +use std::ffi::{VaList, va_copy}; #[link(name = "rust_test_helpers", kind = "static")] extern "C" { @@ -10,35 +10,35 @@ extern "C" { fn rust_valist_interesting_average(_: u64, _: VaList) -> f64; } -pub unsafe extern "C" fn test_valist_forward(n: u64, mut ap: ...) -> f64 { - rust_valist_interesting_average(n, ap.as_va_list()) +pub unsafe extern "C" fn test_valist_forward(n: u64, ap: ...) -> f64 { + rust_valist_interesting_average(n, ap) } -pub unsafe extern "C-unwind" fn c_unwind_can_forward(n: u64, mut ap: ...) -> f64 { - rust_valist_interesting_average(n, ap.as_va_list()) +pub unsafe extern "C-unwind" fn c_unwind_can_forward(n: u64, ap: ...) -> f64 { + rust_valist_interesting_average(n, ap) } pub unsafe extern "C" fn test_va_copy(_: u64, mut ap: ...) { - let mut ap2 = ap.clone(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 30); + let ap2 = va_copy!(ap); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 30); // Advance one pair in the copy before checking - let mut ap2 = ap.clone(); + let mut ap2 = va_copy!(ap); let _ = ap2.arg::(); let _ = ap2.arg::(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 50); // Advance one pair in the original let _ = ap.arg::(); let _ = ap.arg::(); - let mut ap2 = ap.clone(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50); + let ap2 = va_copy!(ap); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 50); - let mut ap2 = ap.clone(); + let mut ap2 = va_copy!(ap); let _ = ap2.arg::(); let _ = ap2.arg::(); - assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 70); + assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 70); } pub fn main() { diff --git a/tests/ui/c-variadic/variadic-ffi-4.rs b/tests/ui/c-variadic/variadic-ffi-4.rs index 8064037942259..03698d3f99624 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.rs +++ b/tests/ui/c-variadic/variadic-ffi-4.rs @@ -2,15 +2,15 @@ #![no_std] #![feature(c_variadic)] -use core::ffi::{VaList, VaListImpl}; +use core::ffi::{VaList, va_copy}; -pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { +pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaList<'f> { ap //~^ ERROR: lifetime may not live long enough //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { ap //~ ERROR: lifetime may not live long enough } @@ -18,21 +18,33 @@ pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { let _ = ap.with_copy(|ap| ap); //~ ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { *ap0 = ap1; //~^ ERROR: lifetime may not live long enough //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { ap0 = &mut ap1; //~^ ERROR: `ap1` does not live long enough //~| ERROR: lifetime may not live long enough //~| ERROR: lifetime may not live long enough } -pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - *ap0 = ap1.clone(); +pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + *ap0 = va_copy!(ap1); //~^ ERROR: lifetime may not live long enough - //~| ERROR: lifetime may not live long enough + //~| ERROR: temporary value dropped while borrowed +} + +pub unsafe extern "C" fn no_escape6<'f>(ap: ...) -> VaList<'f> { + va_copy!(ap) + //~^ ERROR: lifetime may not live long enough + //~| ERROR: cannot return value referencing temporary value +} + +pub unsafe extern "C" fn no_escape7(ap: ...) -> VaList<'static> { + va_copy!(ap) + //~^ ERROR: lifetime may not live long enough + //~| ERROR: cannot return value referencing temporary value } diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index fc9f8036083a6..885e605c0d0f9 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -1,41 +1,41 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `VaListImpl<'1>` +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaList<'f> { + | -- -- has type `VaList<'1>` | | | lifetime `'f` defined here LL | ap | ^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'f` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `VaListImpl<'1>` +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaList<'f> { + | -- -- has type `VaList<'1>` | | | lifetime `'f` defined here LL | ap | ^^ function was supposed to return data with lifetime `'f` but it is returning data with lifetime `'1` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:14:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | -- has type `VaListImpl<'1>` +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + | -- has type `VaList<'1>` LL | ap | ^^ returning this value requires that `'1` must outlive `'static` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance error: lifetime may not live long enough @@ -44,70 +44,74 @@ error: lifetime may not live long enough LL | let _ = ap.with_copy(|ap| ap); | --- ^^ returning this value requires that `'1` must outlive `'2` | | | - | | return type of closure is VaList<'2, '_> - | has type `VaList<'1, '_>` + | | return type of closure is VaList<'2> + | has type `VaList<'1>` + | + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` + = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | *ap0 = ap1; - | ^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | *ap0 = ap1; - | ^^^^ assignment requires that `'2` must outlive `'1` + | ^^^^^^^^^^ assignment requires that `'2` must outlive `'1` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of a mutable reference to `VaListImpl<'_>` + = note: requirement occurs because of a mutable reference to `VaList<'_>` = note: mutable references are invariant over their type parameter = help: see for more information about variance error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaListImpl<'1>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` | - = note: requirement occurs because of a mutable reference to `VaListImpl<'_>` + = note: requirement occurs because of a mutable reference to `VaList<'_>` = note: mutable references are invariant over their type parameter = help: see for more information about variance error[E0597]: `ap1` does not live long enough --> $DIR/variadic-ffi-4.rs:28:11 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | - ------- binding `ap1` declared here +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | - ------- binding `ap1` declared here | | | let's call the lifetime of this reference `'3` LL | ap0 = &mut ap1; @@ -117,36 +121,86 @@ LL | ap0 = &mut ap1; | assignment requires that `ap1` is borrowed for `'3` ... LL | } - | - `ap1` dropped here while still borrowed + | - `ap1` dropped here while still borrowed error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:5 | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `VaList<'1>` | | - | has type `&mut VaListImpl<'1>` -LL | *ap0 = ap1.clone(); - | ^^^^ assignment requires that `'2` must outlive `'1` + | has type `&mut VaList<'2>` +LL | *ap0 = va_copy!(ap1); + | ^^^^^^^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance -error: lifetime may not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/variadic-ffi-4.rs:35:12 | -LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `VaListImpl<'2>` - | | - | has type `&mut VaListImpl<'1>` -LL | *ap0 = ap1.clone(); - | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- has type `&mut VaList<'2>` +LL | *ap0 = va_copy!(ap1); + | -------^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | | + | | creates a temporary value which is freed while still in use + | assignment requires that borrow lasts for `'2` | - = note: requirement occurs because of the type `VaListImpl<'_>`, which makes the generic argument `'_` invariant - = note: the struct `VaListImpl<'f>` is invariant over the parameter `'f` + = note: this error originates in the macro `va_copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:41:5 + | +LL | pub unsafe extern "C" fn no_escape6<'f>(ap: ...) -> VaList<'f> { + | -- -- has type `VaList<'1>` + | | + | lifetime `'f` defined here +LL | va_copy!(ap) + | ^^^^^^^^^^^^ function was supposed to return data with lifetime `'f` but it is returning data with lifetime `'1` + | + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` = help: see for more information about variance + = note: this error originates in the macro `va_copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0515]: cannot return value referencing temporary value + --> $DIR/variadic-ffi-4.rs:41:5 + | +LL | va_copy!(ap) + | ^^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | temporary value created here + | + = note: this error originates in the macro `va_copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:47:5 + | +LL | pub unsafe extern "C" fn no_escape7(ap: ...) -> VaList<'static> { + | -- has type `VaList<'1>` +LL | va_copy!(ap) + | ^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static` + | + = note: requirement occurs because of the type `VaList<'_>`, which makes the generic argument `'_` invariant + = note: the struct `VaList<'a>` is invariant over the parameter `'a` + = help: see for more information about variance + = note: this error originates in the macro `va_copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0515]: cannot return value referencing temporary value + --> $DIR/variadic-ffi-4.rs:47:5 + | +LL | va_copy!(ap) + | ^^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | temporary value created here + | + = note: this error originates in the macro `va_copy` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 11 previous errors +error: aborting due to 15 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0515, E0597, E0716. +For more information about an error, try `rustc --explain E0515`. diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 1cd6d13d56b6b..f0b476f6e1c87 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -31,12 +31,10 @@ extern "C" fn f3_3(..., x: isize) {} const unsafe extern "C" fn f4_1(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic //~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg -//~| 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 @@ -64,7 +62,6 @@ impl X { const fn i_f5(x: isize, ...) {} //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg //~| ERROR functions cannot be both `const` and C-variadic - //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time } trait T { diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index b740cef020055..36fd69eb0c129 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -65,25 +65,25 @@ 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:36:1 + --> $DIR/variadic-ffi-semantic-restrictions.rs:35:1 | LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36 + --> $DIR/variadic-ffi-semantic-restrictions.rs:35: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:41:26 + --> $DIR/variadic-ffi-semantic-restrictions.rs:39: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:41:1 + --> $DIR/variadic-ffi-semantic-restrictions.rs:39:1 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^^^ ^^^ ^^^ C-variadic because of this @@ -92,55 +92,55 @@ LL | const extern "C" fn f4_3(..., x: isize, ...) {} | `const` because of this error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26 + --> $DIR/variadic-ffi-semantic-restrictions.rs:39:26 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} | ^^^ ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:47:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:45:13 | LL | fn e_f2(..., x: isize); | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:54:23 + --> $DIR/variadic-ffi-semantic-restrictions.rs:52:23 | LL | fn i_f1(x: isize, ...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:54:13 | LL | fn i_f2(...) {} | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 | LL | fn i_f3(..., x: isize, ...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 | LL | fn i_f3(..., x: isize, ...) {} | ^^^ ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13 | LL | fn i_f4(..., x: isize, ...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:59:13 | LL | fn i_f4(..., x: isize, ...) {} | ^^^ ^^^ error: functions cannot be both `const` and C-variadic - --> $DIR/variadic-ffi-semantic-restrictions.rs:64:5 + --> $DIR/variadic-ffi-semantic-restrictions.rs:62:5 | LL | const fn i_f5(x: isize, ...) {} | ^^^^^ ^^^ C-variadic because of this @@ -148,83 +148,58 @@ LL | const fn i_f5(x: isize, ...) {} | `const` because of this error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29 + --> $DIR/variadic-ffi-semantic-restrictions.rs:62:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23 + --> $DIR/variadic-ffi-semantic-restrictions.rs:68:23 | LL | fn t_f1(x: isize, ...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:73:23 + --> $DIR/variadic-ffi-semantic-restrictions.rs:70:23 | LL | fn t_f2(x: isize, ...); | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:72:13 | LL | fn t_f3(...) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:74:13 | LL | fn t_f4(...); | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:76:13 | LL | fn t_f5(..., x: isize) {} | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:76:13 | LL | fn t_f5(..., x: isize) {} | ^^^ error: `...` must be the last argument of a C-variadic function - --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 | LL | fn t_f6(..., x: isize); | ^^^ error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg - --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 + --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 | LL | fn t_f6(..., x: isize); | ^^^ -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:32:43 - | -LL | const unsafe extern "C" fn f4_1(x: isize, ...) {} - | ^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36 - | -LL | const extern "C" fn f4_2(x: isize, ...) {} - | ^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time - --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29 - | -LL | const fn i_f5(x: isize, ...) {} - | ^^^ - value is dropped here - | | - | the destructor for this type cannot be evaluated in constant functions - -error: aborting due to 36 previous errors +error: aborting due to 33 previous errors -For more information about this error, try `rustc --explain E0493`.