Rework c_variadic
This commit is contained in:
parent
672388edbe
commit
f7b3c1d3c0
22 changed files with 591 additions and 291 deletions
|
|
@ -36,10 +36,10 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
|
|||
vtable_byte_offset: u64,
|
||||
typeid: Self::Metadata,
|
||||
) -> Self::Value;
|
||||
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
|
||||
/// Trait method used to inject `va_start` on the "spoofed" `VaList` in
|
||||
/// Rust defined C-variadic functions.
|
||||
fn va_start(&mut self, val: Self::Value) -> Self::Value;
|
||||
/// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before
|
||||
/// Trait method used to inject `va_end` on the "spoofed" `VaList` before
|
||||
/// Rust defined C-variadic functions return.
|
||||
fn va_end(&mut self, val: Self::Value) -> Self::Value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@
|
|||
|
||||
#[cfg(not(target_arch = "xtensa"))]
|
||||
use crate::ffi::c_void;
|
||||
#[allow(unused_imports)]
|
||||
use crate::fmt;
|
||||
use crate::intrinsics::{va_arg, va_copy, va_end};
|
||||
use crate::marker::{PhantomData, PhantomInvariantLifetime};
|
||||
use crate::ops::{Deref, DerefMut};
|
||||
use crate::intrinsics::{va_arg, va_copy};
|
||||
use crate::marker::PhantomCovariantLifetime;
|
||||
|
||||
// The name is WIP, using `VaListImpl` for now.
|
||||
//
|
||||
// Most targets explicitly specify the layout of `va_list`, this layout is matched here.
|
||||
// For `va_list`s which are single-element array in C (and therefore experience array-to-pointer
|
||||
// decay when passed as arguments in C), the `VaList` struct is annotated with
|
||||
// `#[rustc_pass_indirectly_in_non_rustic_abis]`. This ensures that the compiler uses the correct
|
||||
// ABI for functions like `extern "C" fn takes_va_list(va: VaList<'_>)` by passing `va` indirectly.
|
||||
crate::cfg_select! {
|
||||
all(
|
||||
target_arch = "aarch64",
|
||||
|
|
@ -27,66 +27,60 @@ crate::cfg_select! {
|
|||
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
stack: *mut c_void,
|
||||
gr_top: *mut c_void,
|
||||
vr_top: *mut c_void,
|
||||
struct VaListInner {
|
||||
stack: *const c_void,
|
||||
gr_top: *const c_void,
|
||||
vr_top: *const c_void,
|
||||
gr_offs: i32,
|
||||
vr_offs: i32,
|
||||
_marker: PhantomInvariantLifetime<'f>,
|
||||
}
|
||||
}
|
||||
all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)) => {
|
||||
/// PowerPC ABI implementation of a `va_list`.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct VaListInner {
|
||||
gpr: u8,
|
||||
fpr: u8,
|
||||
reserved: u16,
|
||||
overflow_arg_area: *mut c_void,
|
||||
reg_save_area: *mut c_void,
|
||||
_marker: PhantomInvariantLifetime<'f>,
|
||||
overflow_arg_area: *const c_void,
|
||||
reg_save_area: *const c_void,
|
||||
}
|
||||
}
|
||||
target_arch = "s390x" => {
|
||||
/// s390x ABI implementation of a `va_list`.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct VaListInner {
|
||||
gpr: i64,
|
||||
fpr: i64,
|
||||
overflow_arg_area: *mut c_void,
|
||||
reg_save_area: *mut c_void,
|
||||
_marker: PhantomInvariantLifetime<'f>,
|
||||
overflow_arg_area: *const c_void,
|
||||
reg_save_area: *const c_void,
|
||||
}
|
||||
}
|
||||
all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)) => {
|
||||
/// x86_64 ABI implementation of a `va_list`.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct VaListInner {
|
||||
gp_offset: i32,
|
||||
fp_offset: i32,
|
||||
overflow_arg_area: *mut c_void,
|
||||
reg_save_area: *mut c_void,
|
||||
_marker: PhantomInvariantLifetime<'f>,
|
||||
overflow_arg_area: *const c_void,
|
||||
reg_save_area: *const c_void,
|
||||
}
|
||||
}
|
||||
target_arch = "xtensa" => {
|
||||
/// Xtensa ABI implementation of a `va_list`.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
stk: *mut i32,
|
||||
reg: *mut i32,
|
||||
#[rustc_pass_indirectly_in_non_rustic_abis]
|
||||
struct VaListInner {
|
||||
stk: *const i32,
|
||||
reg: *const i32,
|
||||
ndx: i32,
|
||||
_marker: PhantomInvariantLifetime<'f>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,94 +89,32 @@ 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 `VaListInner` 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`.
|
||||
#[repr(transparent)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaListImpl<'f> {
|
||||
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>,
|
||||
}
|
||||
|
||||
impl<'f> fmt::Debug for VaListImpl<'f> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "va_list* {:p}", self.ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate::cfg_select! {
|
||||
all(
|
||||
any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "s390x",
|
||||
target_arch = "x86_64"
|
||||
),
|
||||
not(target_arch = "xtensa"),
|
||||
any(not(target_arch = "aarch64"), not(target_vendor = "apple")),
|
||||
not(target_family = "wasm"),
|
||||
not(target_os = "uefi"),
|
||||
not(windows),
|
||||
) => {
|
||||
/// 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>>,
|
||||
}
|
||||
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
/// 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>>,
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
struct VaListInner {
|
||||
ptr: *const c_void,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'f: 'a> Deref for VaList<'a, 'f> {
|
||||
type Target = VaListImpl<'f>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &VaListImpl<'f> {
|
||||
&self.inner
|
||||
}
|
||||
/// A variable argument list, equivalent to `va_list` in C.
|
||||
#[repr(transparent)]
|
||||
#[lang = "va_list"]
|
||||
pub struct VaList<'a> {
|
||||
inner: VaListInner,
|
||||
_marker: PhantomCovariantLifetime<'a>,
|
||||
}
|
||||
|
||||
impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut VaListImpl<'f> {
|
||||
&mut self.inner
|
||||
impl fmt::Debug for VaList<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// No need to include `_marker` in debug output.
|
||||
f.debug_tuple("VaList").field(&self.inner).finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +135,7 @@ mod sealed {
|
|||
impl<T> Sealed for *const T {}
|
||||
}
|
||||
|
||||
/// Types that are valid to read using [`VaListImpl::arg`].
|
||||
/// Types that are valid to read using [`VaList::arg`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
|
@ -238,7 +170,7 @@ unsafe impl VaArgSafe for f64 {}
|
|||
unsafe impl<T> VaArgSafe for *mut T {}
|
||||
unsafe impl<T> VaArgSafe for *const T {}
|
||||
|
||||
impl<'f> VaListImpl<'f> {
|
||||
impl<'f> VaList<'f> {
|
||||
/// Advance to and read the next variable argument.
|
||||
///
|
||||
/// # Safety
|
||||
|
|
@ -258,27 +190,13 @@ impl<'f> VaListImpl<'f> {
|
|||
// 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<F, R>(&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> {
|
||||
impl<'f> Clone for VaList<'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
|
||||
// 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()
|
||||
|
|
@ -286,18 +204,11 @@ impl<'f> Clone for VaListImpl<'f> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'f> Drop for VaListImpl<'f> {
|
||||
impl<'f> Drop for VaList<'f> {
|
||||
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,
|
||||
// so the `va_end` would get directly called from the same function as
|
||||
// the corresponding `va_copy`. `man va_end` states that C requires this,
|
||||
// and LLVM basically follows the C semantics, so we need to make sure
|
||||
// that `va_end` is always called from the same function as `va_copy`.
|
||||
// For more details, see https://github.com/rust-lang/rust/pull/59625
|
||||
// and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
|
||||
//
|
||||
// This works for now, since `va_end` is a no-op on all current LLVM targets.
|
||||
// Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour
|
||||
// (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this
|
||||
// destructor is empty.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::ffi::va_list::{VaArgSafe, VaListImpl};
|
||||
use crate::ffi::va_list::{VaArgSafe, VaList};
|
||||
use crate::marker::{ConstParamTy, Destruct, DiscriminantKind, PointeeSized, Tuple};
|
||||
use crate::{mem, ptr};
|
||||
|
||||
|
|
@ -3447,7 +3447,7 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
|
|||
///
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
|
||||
pub unsafe fn va_copy<'f>(dest: *mut VaList<'f>, src: &VaList<'f>);
|
||||
|
||||
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
|
||||
/// argument `ap` points to.
|
||||
|
|
@ -3465,7 +3465,7 @@ pub unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
|
|||
///
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
|
||||
pub unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaList<'_>) -> T;
|
||||
|
||||
/// Destroy the arglist `ap` after initialization with `va_start` or `va_copy`.
|
||||
///
|
||||
|
|
@ -3475,4 +3475,4 @@ pub unsafe fn va_arg<T: VaArgSafe>(ap: &mut VaListImpl<'_>) -> T;
|
|||
///
|
||||
#[rustc_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub unsafe fn va_end(ap: &mut VaListImpl<'_>);
|
||||
pub unsafe fn va_end(ap: &mut VaList<'_>);
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
#[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,
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"ignore-thumbv8m.base-none-eabi",
|
||||
"ignore-thumbv8m.main-none-eabi",
|
||||
"ignore-tvos",
|
||||
"ignore-uefi",
|
||||
"ignore-unix",
|
||||
"ignore-unknown",
|
||||
"ignore-uwp",
|
||||
|
|
|
|||
|
|
@ -314,6 +314,10 @@ double rust_interesting_average(uint64_t n, ...) {
|
|||
return sum;
|
||||
}
|
||||
|
||||
int32_t rust_va_list_next_i32(va_list* ap) {
|
||||
return va_arg(*ap, int32_t);
|
||||
}
|
||||
|
||||
int32_t rust_int8_to_int32(int8_t x) {
|
||||
return (int32_t)x;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy`
|
||||
// Tests that `VaList::clone` gets inlined into a call to `llvm.va_copy`
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(c_variadic)]
|
||||
|
|
@ -12,5 +12,5 @@ extern "C" {
|
|||
pub unsafe extern "C" fn clone_variadic(ap: VaList) {
|
||||
let mut ap2 = ap.clone();
|
||||
// CHECK: call void @llvm.va_copy
|
||||
foreign_c_variadic_1(ap2.as_va_list(), 42i32);
|
||||
foreign_c_variadic_1(ap2, 42i32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@ extern "C" {
|
|||
}
|
||||
|
||||
// Ensure that `va_start` and `va_end` are properly injected even
|
||||
// when the "spoofed" `VaListImpl` is not used.
|
||||
// when the "spoofed" `VaList` is not used.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut 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 `VaList::clone` 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 {
|
||||
// CHECK: call void @llvm.va_start
|
||||
let mut ap2 = ap.clone();
|
||||
// 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ needs-unwind
|
||||
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
|
||||
//
|
||||
//@ min-llvm-version: 21
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(c_variadic)]
|
||||
|
|
@ -25,23 +25,23 @@ pub unsafe extern "C" fn use_foreign_c_variadic_0() {
|
|||
}
|
||||
|
||||
// Ensure that we do not remove the `va_list` passed to the foreign function when
|
||||
// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
|
||||
// removing the "spoofed" `VaList` that is used by Rust defined C-variadics.
|
||||
pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap)
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0)
|
||||
foreign_c_variadic_1(ap);
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 42)
|
||||
foreign_c_variadic_1(ap, 42i32);
|
||||
}
|
||||
pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42)
|
||||
foreign_c_variadic_1(ap, 2i32, 42i32);
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
|
||||
// CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %0, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
|
||||
foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#![feature(c_variadic)]
|
||||
#![feature(cfg_select)]
|
||||
|
||||
use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong};
|
||||
use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong};
|
||||
|
||||
macro_rules! continue_if {
|
||||
($cond:expr) => {
|
||||
|
|
@ -58,11 +58,8 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
|
|||
continue_if!(ap.arg::<c_int>() == 16);
|
||||
continue_if!(ap.arg::<c_int>() == 'A' as c_int);
|
||||
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
|
||||
ap.with_copy(
|
||||
|mut ap| {
|
||||
if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff }
|
||||
},
|
||||
)
|
||||
let mut ap = ap.clone();
|
||||
if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
|
@ -153,8 +150,8 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
|
|||
unsafe extern "C" {
|
||||
fn test_variadic(_: c_int, ...) -> usize;
|
||||
fn test_va_list_by_value(_: VaList) -> usize;
|
||||
fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize;
|
||||
fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize;
|
||||
fn test_va_list_by_pointer(_: *mut VaList) -> usize;
|
||||
fn test_va_list_by_pointer_pointer(_: *mut *mut VaList) -> usize;
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
|
@ -165,7 +162,7 @@ extern "C" fn run_test_variadic() -> usize {
|
|||
#[unsafe(no_mangle)]
|
||||
extern "C" fn run_test_va_list_by_value() -> usize {
|
||||
unsafe extern "C" fn helper(mut ap: ...) -> usize {
|
||||
unsafe { test_va_list_by_value(ap.as_va_list()) }
|
||||
unsafe { test_va_list_by_value(ap) }
|
||||
}
|
||||
|
||||
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
|
||||
|
|
|
|||
|
|
@ -10,37 +10,45 @@ extern "C" {
|
|||
fn rust_interesting_average(_: u64, ...) -> f64;
|
||||
|
||||
fn rust_valist_interesting_average(_: u64, _: VaList) -> f64;
|
||||
|
||||
fn rust_va_list_next_i32(_: *mut VaList<'_>) -> i32;
|
||||
}
|
||||
|
||||
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 = ap.clone();
|
||||
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 _ = ap2.arg::<u64>();
|
||||
let _ = ap2.arg::<f64>();
|
||||
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::<u64>();
|
||||
let _ = ap.arg::<f64>();
|
||||
|
||||
let mut ap2 = ap.clone();
|
||||
assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 50);
|
||||
let ap2 = ap.clone();
|
||||
assert_eq!(rust_valist_interesting_average(2, ap2) as i64, 50);
|
||||
|
||||
let mut ap2 = ap.clone();
|
||||
let _ = ap2.arg::<u64>();
|
||||
let _ = ap2.arg::<f64>();
|
||||
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 unsafe extern "C" fn test_ref(mut ap: ...) {
|
||||
assert_eq!(rust_va_list_next_i32(&mut ap), 2);
|
||||
assert_eq!(rust_va_list_next_i32(&mut ap), 4);
|
||||
assert_eq!(rust_va_list_next_i32(&mut ap), 8);
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
|
|
@ -85,4 +93,8 @@ pub fn main() {
|
|||
unsafe {
|
||||
test_va_copy(4, 10i64, 10f64, 20i64, 20f64, 30i64, 30f64, 40i64, 40f64);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
test_ref(2, 4, 8);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
80
tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr
Normal file
80
tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
error: fn_abi_of(take_va_list) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: VaList<'_>,
|
||||
layout: Layout {
|
||||
size: Size(32 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: $OFFSETS,
|
||||
memory_index: $MEMORY_INDEX,
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Indirect {
|
||||
attrs: ArgAttributes {
|
||||
regular: CapturesAddress | NoAlias | NonNull | NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(32 bytes),
|
||||
pointee_align: Some(
|
||||
Align(8 bytes),
|
||||
),
|
||||
},
|
||||
meta_attrs: None,
|
||||
on_stack: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: C,
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-by-value-abi.rs:26:1
|
||||
|
|
||||
LL | pub extern "C" fn take_va_list(_: VaList<'_>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
46
tests/ui/c-variadic/pass-by-value-abi.rs
Normal file
46
tests/ui/c-variadic/pass-by-value-abi.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//@ check-fail
|
||||
//@ normalize-stderr: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
|
||||
//@ normalize-stderr: "valid_range: 0\.\.=\d+" -> "valid_range: 0..=$$MAX"
|
||||
//@ normalize-stderr: "memory_index: \[[^\]]+\]" -> "memory_index: $$MEMORY_INDEX"
|
||||
//@ normalize-stderr: "offsets: \[[^\]]+\]" -> "offsets: $$OFFSETS"
|
||||
//@ revisions: x86_64 aarch64 win
|
||||
//@ compile-flags: -O
|
||||
//@ [x86_64] only-x86_64
|
||||
//@ [x86_64] ignore-windows
|
||||
//@ [x86_64] ignore-uefi
|
||||
//@ [aarch64] only-aarch64
|
||||
//@ [aarch64] ignore-windows
|
||||
//@ [aarch64] ignore-apple
|
||||
//@ [aarch64] ignore-uefi
|
||||
// Windows dosen't use `#[rustc_pass_indirectly_in_non_rustic_abis]` and is tested in CI, so is here
|
||||
// for comparison.
|
||||
//@ [win] only-windows
|
||||
|
||||
#![feature(rustc_attrs, c_variadic)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Can't use `minicore` here as this is testing the implementation in `core::ffi` specifically.
|
||||
use std::ffi::VaList;
|
||||
|
||||
#[rustc_abi(debug)]
|
||||
pub extern "C" fn take_va_list(_: VaList<'_>) {}
|
||||
//~^ ERROR fn_abi_of(take_va_list) = FnAbi {
|
||||
//[x86_64]~^^ ERROR mode: Indirect {
|
||||
//[x86_64]~^^^ ERROR on_stack: false,
|
||||
//[aarch64]~^^^^ ERROR mode: Indirect {
|
||||
//[aarch64]~^^^^^ ERROR on_stack: false,
|
||||
//[win]~^^^^^^ ERROR mode: Direct(
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", not(windows)))]
|
||||
#[rustc_abi(debug)]
|
||||
pub extern "sysv64" fn take_va_list_sysv64(_: VaList<'_>) {}
|
||||
//[x86_64]~^ ERROR fn_abi_of(take_va_list_sysv64) = FnAbi {
|
||||
//[x86_64]~^^ ERROR mode: Indirect {
|
||||
//[x86_64]~^^^ ERROR on_stack: false,
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", not(windows)))]
|
||||
#[rustc_abi(debug)]
|
||||
pub extern "win64" fn take_va_list_win64(_: VaList<'_>) {}
|
||||
//[x86_64]~^ ERROR: fn_abi_of(take_va_list_win64) = FnAbi {
|
||||
//[x86_64]~^^ ERROR mode: Indirect {
|
||||
//[x86_64]~^^^ ERROR on_stack: false,
|
||||
83
tests/ui/c-variadic/pass-by-value-abi.win.stderr
Normal file
83
tests/ui/c-variadic/pass-by-value-abi.win.stderr
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
error: fn_abi_of(take_va_list) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: VaList<'_>,
|
||||
layout: Layout {
|
||||
size: Size(8 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Scalar(
|
||||
Initialized {
|
||||
value: Pointer(
|
||||
AddressSpace(
|
||||
0,
|
||||
),
|
||||
),
|
||||
valid_range: 0..=$MAX,
|
||||
},
|
||||
),
|
||||
fields: Arbitrary {
|
||||
offsets: $OFFSETS,
|
||||
memory_index: $MEMORY_INDEX,
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Direct(
|
||||
ArgAttributes {
|
||||
regular: NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(0 bytes),
|
||||
pointee_align: None,
|
||||
},
|
||||
),
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: C,
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-by-value-abi.rs:26:1
|
||||
|
|
||||
LL | pub extern "C" fn take_va_list(_: VaList<'_>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
240
tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr
Normal file
240
tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
error: fn_abi_of(take_va_list) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: VaList<'_>,
|
||||
layout: Layout {
|
||||
size: Size(24 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: $OFFSETS,
|
||||
memory_index: $MEMORY_INDEX,
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Indirect {
|
||||
attrs: ArgAttributes {
|
||||
regular: CapturesAddress | NoAlias | NonNull | NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(24 bytes),
|
||||
pointee_align: Some(
|
||||
Align(8 bytes),
|
||||
),
|
||||
},
|
||||
meta_attrs: None,
|
||||
on_stack: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: C,
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-by-value-abi.rs:26:1
|
||||
|
|
||||
LL | pub extern "C" fn take_va_list(_: VaList<'_>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: fn_abi_of(take_va_list_sysv64) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: VaList<'_>,
|
||||
layout: Layout {
|
||||
size: Size(24 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: $OFFSETS,
|
||||
memory_index: $MEMORY_INDEX,
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Indirect {
|
||||
attrs: ArgAttributes {
|
||||
regular: CapturesAddress | NoAlias | NonNull | NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(24 bytes),
|
||||
pointee_align: Some(
|
||||
Align(8 bytes),
|
||||
),
|
||||
},
|
||||
meta_attrs: None,
|
||||
on_stack: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: X86(
|
||||
SysV64,
|
||||
),
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-by-value-abi.rs:36:1
|
||||
|
|
||||
LL | pub extern "sysv64" fn take_va_list_sysv64(_: VaList<'_>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: fn_abi_of(take_va_list_win64) = FnAbi {
|
||||
args: [
|
||||
ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: VaList<'_>,
|
||||
layout: Layout {
|
||||
size: Size(24 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(8 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: $OFFSETS,
|
||||
memory_index: $MEMORY_INDEX,
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(8 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Indirect {
|
||||
attrs: ArgAttributes {
|
||||
regular: CapturesAddress | NoAlias | NonNull | NoUndef,
|
||||
arg_ext: None,
|
||||
pointee_size: Size(24 bytes),
|
||||
pointee_align: Some(
|
||||
Align(8 bytes),
|
||||
),
|
||||
},
|
||||
meta_attrs: None,
|
||||
on_stack: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
ret: ArgAbi {
|
||||
layout: TyAndLayout {
|
||||
ty: (),
|
||||
layout: Layout {
|
||||
size: Size(0 bytes),
|
||||
align: AbiAlign {
|
||||
abi: Align(1 bytes),
|
||||
},
|
||||
backend_repr: Memory {
|
||||
sized: true,
|
||||
},
|
||||
fields: Arbitrary {
|
||||
offsets: [],
|
||||
memory_index: [],
|
||||
},
|
||||
largest_niche: None,
|
||||
uninhabited: false,
|
||||
variants: Single {
|
||||
index: 0,
|
||||
},
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: Align(1 bytes),
|
||||
randomization_seed: $SEED,
|
||||
},
|
||||
},
|
||||
mode: Ignore,
|
||||
},
|
||||
c_variadic: false,
|
||||
fixed_count: 1,
|
||||
conv: X86(
|
||||
Win64,
|
||||
),
|
||||
can_unwind: false,
|
||||
}
|
||||
--> $DIR/pass-by-value-abi.rs:43:1
|
||||
|
|
||||
LL | pub extern "win64" fn take_va_list_win64(_: VaList<'_>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
@ -2,37 +2,30 @@
|
|||
#![no_std]
|
||||
#![feature(c_variadic)]
|
||||
|
||||
use core::ffi::{VaList, VaListImpl};
|
||||
use core::ffi::VaList;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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: ...) {
|
||||
pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
|
||||
*ap0 = ap1.clone();
|
||||
//~^ ERROR: lifetime may not live long enough
|
||||
//~| ERROR: lifetime may not live long enough
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,113 +1,64 @@
|
|||
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>`
|
||||
| |
|
||||
| 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/variadic-ffi-4.rs:14:5
|
||||
--> $DIR/variadic-ffi-4.rs:13: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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/variadic-ffi-4.rs:18:31
|
||||
--> $DIR/variadic-ffi-4.rs:17:5
|
||||
|
|
||||
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, '_>`
|
||||
|
||||
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<'1>`
|
||||
| |
|
||||
| has type `&mut VaListImpl<'1>`
|
||||
| has type `&mut VaList<'2>`
|
||||
LL | *ap0 = 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> 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_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
|
||||
| ------- ------- has type `VaList<'2>`
|
||||
| |
|
||||
| has type `&mut VaListImpl<'1>`
|
||||
LL | *ap0 = ap1;
|
||||
| ^^^^ 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> 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>`
|
||||
| |
|
||||
| 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 <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/variadic-ffi-4.rs:28:5
|
||||
--> $DIR/variadic-ffi-4.rs:22: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 <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error[E0597]: `ap1` does not live long enough
|
||||
--> $DIR/variadic-ffi-4.rs:28:11
|
||||
--> $DIR/variadic-ffi-4.rs:22: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;
|
||||
|
|
@ -120,33 +71,15 @@ LL | }
|
|||
| - `ap1` dropped here while still borrowed
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/variadic-ffi-4.rs:35:5
|
||||
--> $DIR/variadic-ffi-4.rs:29: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>`
|
||||
| has type `&mut VaList<'2>`
|
||||
LL | *ap0 = ap1.clone();
|
||||
| ^^^^ 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
| ^^^^ assignment requires that `'1` must outlive `'2`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $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`
|
||||
|
|
||||
= 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`
|
||||
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0597`.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// A bare `...` represents `CVarArgs` (`VaListImpl<'_>`) in function argument type
|
||||
// A bare `...` represents `CVarArgs` (`VaList<'_>`) in function argument type
|
||||
// position without being a proper type syntactically.
|
||||
// This test ensures that we do not regress certain MBE calls would we ever promote
|
||||
// `...` to a proper type syntactically.
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ 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
|
||||
//~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
|
||||
const extern "C" fn f4_2(x: isize, _: ...) {}
|
||||
//~^ ERROR functions cannot be both `const` and C-variadic
|
||||
//~| ERROR functions with a C variable argument list must be unsafe
|
||||
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
|
||||
//~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
|
||||
const extern "C" fn f4_3(_: ..., x: isize, _: ...) {}
|
||||
//~^ ERROR functions cannot be both `const` and C-variadic
|
||||
|
|
@ -65,7 +65,7 @@ impl X {
|
|||
const fn i_f5(x: isize, _: ...) {}
|
||||
//~^ ERROR `...` is not supported for non-extern functions
|
||||
//~| ERROR functions cannot be both `const` and C-variadic
|
||||
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
|
||||
//~| ERROR destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
}
|
||||
|
||||
trait T {
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ error: `...` must be the last argument of a C-variadic function
|
|||
LL | fn t_f6(_: ..., x: isize);
|
||||
| ^^^^^^
|
||||
|
||||
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
|
||||
error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
--> $DIR/variadic-ffi-semantic-restrictions.rs:33:43
|
||||
|
|
||||
LL | const unsafe extern "C" fn f4_1(x: isize, _: ...) {}
|
||||
|
|
@ -244,7 +244,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, _: ...) {}
|
|||
| |
|
||||
| the destructor for this type cannot be evaluated in constant functions
|
||||
|
||||
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
|
||||
error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
--> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
|
||||
|
|
||||
LL | const extern "C" fn f4_2(x: isize, _: ...) {}
|
||||
|
|
@ -252,7 +252,7 @@ LL | const extern "C" fn f4_2(x: isize, _: ...) {}
|
|||
| |
|
||||
| the destructor for this type cannot be evaluated in constant functions
|
||||
|
||||
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
|
||||
error[E0493]: destructor of `VaList<'_>` cannot be evaluated at compile-time
|
||||
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
|
||||
|
|
||||
LL | const fn i_f5(x: isize, _: ...) {}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ params: [
|
|||
)
|
||||
}
|
||||
Param {
|
||||
ty: std::ffi::VaListImpl<'{erased}>
|
||||
ty: std::ffi::VaList<'{erased}>
|
||||
ty_span: None
|
||||
self_kind: None
|
||||
hir_id: Some(HirId(DefId(0:3 ~ c_variadic[a5de]::foo).3))
|
||||
param: Some(
|
||||
Pat: {
|
||||
ty: std::ffi::VaListImpl<'{erased}>
|
||||
ty: std::ffi::VaList<'{erased}>
|
||||
span: $DIR/c-variadic.rs:7:34: 7:37 (#0)
|
||||
kind: PatKind {
|
||||
Missing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue