diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index 2906e5824ae..49090fb8e43 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -5,6 +5,8 @@ //! Utilities related to FFI bindings. use crate::fmt; +use crate::marker::PhantomData; +use crate::ops::{Deref, DerefMut}; /// Equivalent to C's `void` type when used as a [pointer]. /// @@ -45,25 +47,33 @@ impl fmt::Debug for c_void { } /// Basic implementation of a `va_list`. +// The name is WIP, using `VaListImpl` for now. #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), + windows))] +#[repr(transparent)] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + ptr: *mut c_void, + _marker: PhantomData<&'f c_void>, +} + +#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), all(target_arch = "aarch64", target_os = "ios"), windows))] #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -extern { - type VaListImpl; -} - -#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - all(target_arch = "aarch64", target_os = "ios"), - windows))] -impl fmt::Debug for VaListImpl { +impl<'f> fmt::Debug for VaListImpl<'f> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "va_list* {:p}", self) + write!(f, "va_list* {:p}", self.ptr) } } @@ -79,12 +89,14 @@ impl fmt::Debug for VaListImpl { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { +#[lang = "va_list"] +pub struct VaListImpl<'f> { stack: *mut c_void, gr_top: *mut c_void, vr_top: *mut c_void, gr_offs: i32, vr_offs: i32, + _marker: PhantomData<&'f c_void>, } /// PowerPC ABI implementation of a `va_list`. @@ -95,12 +107,14 @@ struct VaListImpl { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { +#[lang = "va_list"] +pub struct VaListImpl<'f> { gpr: u8, fpr: u8, reserved: u16, overflow_arg_area: *mut c_void, reg_save_area: *mut c_void, + _marker: PhantomData<&'f c_void>, } /// x86_64 ABI implementation of a `va_list`. @@ -111,22 +125,131 @@ struct VaListImpl { reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -struct VaListImpl { +#[lang = "va_list"] +pub struct VaListImpl<'f> { gp_offset: i32, fp_offset: i32, overflow_arg_area: *mut c_void, reg_save_area: *mut c_void, + _marker: PhantomData<&'f c_void>, +} + +/// asm.js ABI implementation of a `va_list`. +// asm.js uses the PNaCl ABI, which specifies that a `va_list` is +// an array of 4 32-bit integers, according to the old PNaCl docs at +// https://web.archive.org/web/20130518054430/https://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Derived-Types +// and clang does the same in `CreatePNaClABIBuiltinVaListDecl` from `lib/AST/ASTContext.cpp` +#[cfg(all(target_arch = "asmjs", not(windows)))] +#[repr(C)] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[lang = "va_list"] +pub struct VaListImpl<'f> { + inner: [crate::mem::MaybeUninit; 4], + _marker: PhantomData<&'f c_void>, +} + +#[cfg(all(target_arch = "asmjs", not(windows)))] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> fmt::Debug for VaListImpl<'f> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unsafe { + write!(f, "va_list* [{:#x}, {:#x}, {:#x}, {:#x}]", + self.inner[0].read(), self.inner[1].read(), + self.inner[2].read(), self.inner[3].read()) + } + } } /// A wrapper for a `va_list` -#[lang = "va_list"] +#[repr(transparent)] #[derive(Debug)] #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -#[repr(transparent)] -pub struct VaList<'a>(&'a mut VaListImpl); +pub struct VaList<'a, 'f: 'a> { + #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), + windows))] + inner: VaListImpl<'f>, + + #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", + target_arch = "x86_64", target_arch = "asmjs"), + any(not(target_arch = "aarch64"), not(target_os = "ios")), + not(windows)))] + inner: &'a mut VaListImpl<'f>, + + _marker: PhantomData<&'a mut VaListImpl<'f>>, +} + +#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), + not(target_arch = "x86_64"), not(target_arch = "asmjs")), + all(target_arch = "aarch64", target_os = "ios"), + windows))] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> VaListImpl<'f> { + /// Convert 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, + } + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", + target_arch = "x86_64", target_arch = "asmjs"), + any(not(target_arch = "aarch64"), not(target_os = "ios")), + not(windows)))] +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'f> VaListImpl<'f> { + /// Convert 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, + } + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'a, 'f: 'a> Deref for VaList<'a, 'f> { + type Target = VaListImpl<'f>; + + #[inline] + fn deref(&self) -> &VaListImpl<'f> { + &self.inner + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { + #[inline] + fn deref_mut(&mut self) -> &mut VaListImpl<'f> { + &mut self.inner + } +} // The VaArgSafe trait needs to be used in public interfaces, however, the trait // itself must not be allowed to be used outside this module. Allowing users to @@ -175,56 +298,76 @@ impl sealed_trait::VaArgSafe for *mut T {} issue = "44930")] impl sealed_trait::VaArgSafe for *const T {} -impl<'a> VaList<'a> { +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> VaListImpl<'f> { /// Advance to the next arg. - #[unstable(feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930")] + #[inline] pub unsafe fn arg(&mut self) -> T { va_arg(self) } /// Copies the `va_list` at the current location. - #[unstable(feature = "c_variadic", - reason = "the `c_variadic` feature has not been properly tested on \ - all supported platforms", - issue = "44930")] pub unsafe fn with_copy(&self, f: F) -> R - where F: for<'copy> FnOnce(VaList<'copy>) -> R { - #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - all(target_arch = "aarch64", target_os = "ios"), - windows))] - let mut ap = va_copy(self); - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows), not(all(target_arch = "aarch64", target_os = "ios"))))] - let mut ap_inner = va_copy(self); - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows), not(all(target_arch = "aarch64", target_os = "ios"))))] - let mut ap = VaList(&mut ap_inner); - let ret = f(VaList(ap.0)); + where F: for<'copy> FnOnce(VaList<'copy, 'f>) -> R { + let mut ap = self.clone(); + let ret = f(ap.as_va_list()); va_end(&mut ap); ret } } +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> Clone for VaListImpl<'f> { + #[inline] + fn clone(&self) -> Self { + let mut dest = crate::mem::MaybeUninit::uninit(); + unsafe { + va_copy(dest.as_mut_ptr(), self); + dest.assume_init() + } + } +} + +#[unstable(feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930")] +#[cfg(not(bootstrap))] +impl<'f> Drop for VaListImpl<'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. + } +} + extern "rust-intrinsic" { /// Destroy the arglist `ap` after initialization with `va_start` or /// `va_copy`. - fn va_end(ap: &mut VaList<'_>); + #[cfg(not(bootstrap))] + fn va_end(ap: &mut VaListImpl<'_>); /// Copies the current location of arglist `src` to the arglist `dst`. - #[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"), - not(target_arch = "x86_64")), - all(target_arch = "aarch64", target_os = "ios"), - windows))] - fn va_copy<'a>(src: &VaList<'a>) -> VaList<'a>; - #[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc", target_arch = "x86_64"), - not(windows), not(all(target_arch = "aarch64", target_os = "ios"))))] - fn va_copy(src: &VaList<'_>) -> VaListImpl; + #[cfg(not(bootstrap))] + fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. - fn va_arg(ap: &mut VaList<'_>) -> T; + #[cfg(not(bootstrap))] + fn va_arg(ap: &mut VaListImpl<'_>) -> T; } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 153397f11b5..c4f7b78a133 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1674,7 +1674,7 @@ impl<'a> LoweringContext<'a> { } TyKind::Mac(_) => bug!("`TyMac` should have been expanded by now."), TyKind::CVarArgs => { - // Create the implicit lifetime of the "spoofed" `VaList`. + // Create the implicit lifetime of the "spoofed" `VaListImpl`. let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); let lt = self.new_implicit_lifetime(span); hir::TyKind::CVarArgs(lt) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0884a726a27..a88eeaa5ee2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1930,7 +1930,7 @@ pub enum TyKind { Infer, /// Placeholder for a type that has failed to be defined. Err, - /// Placeholder for C-variadic arguments. We "spoof" the `VaList` created + /// Placeholder for C-variadic arguments. We "spoof" the `VaListImpl` created /// from the variadic arguments. This type is only valid up to typeck. CVarArgs(Lifetime), } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6cee2709b63..9ce1d2eec5d 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2711,7 +2711,7 @@ where } // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaList` + // and there is one or more fixed arguments; ensure that the `VaListImpl` // is ignored as an argument. if sig.c_variadic { match (last_arg_idx, arg_idx) { @@ -2722,7 +2722,7 @@ where }; match ty.sty { ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaList`. Set the arguments mode + // This is the "spoofed" `VaListImpl`. Set the arguments mode // so that it will be ignored. arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index dc3631e2ee1..7831c200114 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -146,15 +146,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.va_end(args[0].immediate()) } "va_copy" => { - let va_list = match (tcx.lang_items().va_list(), &result.layout.ty.sty) { - (Some(did), ty::Adt(def, _)) if def.did == did => args[0].immediate(), - (Some(_), _) => self.load(args[0].immediate(), - tcx.data_layout.pointer_align.abi), - (None, _) => bug!("`va_list` language item must be defined") - }; let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); - self.call(intrinsic, &[llresult, va_list], None); - return; + self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) } "va_arg" => { match fn_ty.ret.layout.abi { @@ -743,37 +736,12 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } - fn va_start(&mut self, list: &'ll Value) -> &'ll Value { - let target = &self.cx.tcx.sess.target.target; - let arch = &target.arch; - // A pointer to the architecture specific structure is passed to this - // function. For pointer variants (i686, RISC-V, Windows, etc), we - // should do do nothing, as the address to the pointer is needed. For - // architectures with a architecture specific structure (`Aarch64`, - // `X86_64`, etc), this function should load the structure from the - // address provided. - let va_list = match &**arch { - _ if target.options.is_like_windows => list, - "aarch64" if target.target_os == "ios" => list, - "aarch64" | "x86_64" | "powerpc" => - self.load(list, self.tcx().data_layout.pointer_align.abi), - _ => list, - }; + fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value { let intrinsic = self.cx().get_intrinsic("llvm.va_start"); self.call(intrinsic, &[va_list], None) } - fn va_end(&mut self, list: &'ll Value) -> &'ll Value { - let target = &self.cx.tcx.sess.target.target; - let arch = &target.arch; - // See the comment in `va_start` for the purpose of the following. - let va_list = match &**arch { - _ if target.options.is_like_windows => list, - "aarch64" if target.target_os == "ios" => list, - "aarch64" | "x86_64" | "powerpc" => - self.load(list, self.tcx().data_layout.pointer_align.abi), - _ => list, - }; + fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value { let intrinsic = self.cx().get_intrinsic("llvm.va_end"); self.call(intrinsic, &[va_list], None) } diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 410e00fe0b8..86b0ad761af 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -132,16 +132,6 @@ pub(super) fn emit_va_arg( // For all other architecture/OS combinations fall back to using // the LLVM va_arg instruction. // https://llvm.org/docs/LangRef.html#va-arg-instruction - _ => { - let va_list = if (target.arch == "aarch64" || - target.arch == "x86_64" || - target.arch == "powerpc") && - !target.options.is_like_windows { - bx.load(addr.immediate(), bx.tcx().data_layout.pointer_align.abi) - } else { - addr.immediate() - }; - bx.va_arg(va_list, bx.cx.layout_of(target_ty).llvm_type(bx.cx)) - } + _ => bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b4acc400546..941166ccfab 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -503,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // The "spoofed" `VaList` added to a C-variadic functions signature + // The "spoofed" `VaListImpl` added to a C-variadic functions signature // should not be included in the `extra_args` calculation. let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 }; let extra_args = &args[extra_args_start_idx..]; @@ -687,7 +687,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&args[..], None) }; - // Useful determining if the current argument is the "spoofed" `VaList` + // Useful determining if the current argument is the "spoofed" `VaListImpl` let last_arg_idx = if sig.inputs().is_empty() { None } else { @@ -695,7 +695,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; 'make_args: for (i, arg) in first_args.iter().enumerate() { // If this is a C-variadic function the function signature contains - // an "spoofed" `VaList`. This argument is ignored, but we need to + // an "spoofed" `VaListImpl`. This argument is ignored, but we need to // populate it with a dummy operand so that the users real arguments // are not overwritten. let i = if sig.c_variadic && last_arg_idx.map(|x| i >= x).unwrap_or(false) { diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index c20be56ba0c..e7517d69991 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -83,7 +83,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { scopes: IndexVec>, /// If this function is a C-variadic function, this contains the `PlaceRef` of the - /// "spoofed" `VaList`. + /// "spoofed" `VaListImpl`. va_list_ref: Option>, } @@ -562,35 +562,24 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( indirect_operand.store(bx, tmp); tmp } else { + let tmp = PlaceRef::alloca(bx, arg.layout, &name); if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { - let va_list_impl = match arg_decl.ty.ty_adt_def() { - Some(adt) => adt.non_enum_variant(), - None => bug!("`va_list` language item improperly constructed") + let va_list_did = match tcx.lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), }; - match tcx.type_of(va_list_impl.fields[0].did).sty { - ty::Ref(_, ty, _) => { - // If the underlying structure the `VaList` contains is a structure, - // we need to allocate it (e.g., X86_64 on Linux). - let tmp = PlaceRef::alloca(bx, arg.layout, &name); - if let ty::Adt(..) = ty.sty { - let layout = bx.layout_of(ty); - // Create an unnamed allocation for the backing structure - // and store it in the the spoofed `VaList`. - let backing = PlaceRef::alloca(bx, layout, ""); - bx.store(backing.llval, tmp.llval, layout.align.abi); - } - // Call `va_start` on the spoofed `VaList`. + match arg_decl.ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // Call `va_start` on the spoofed `VaListImpl`. bx.va_start(tmp.llval); *va_list_ref = Some(tmp); - tmp - } - _ => bug!("improperly constructed `va_list` lang item"), + }, + _ => bug!("last argument of variadic function is not a `va_list`") } } else { - let tmp = PlaceRef::alloca(bx, arg.layout, &name); bx.store_fn_arg(arg, &mut llarg_idx, tmp); - tmp } + tmp }; let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use; arg_scope.map(|scope| { diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index cd527898977..ede30a0bed7 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -20,10 +20,10 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - /// Trait method used to inject `va_start` on the "spoofed" `VaList` in + /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` 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" `VaList` before + /// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before /// Rust defined C-variadic functions return. fn va_end(&mut self, val: Self::Value) -> Self::Value; } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 2b99e2d9144..5f052f65333 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -892,7 +892,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); let inputs = if sig.c_variadic { - // Don't include the spoofed `VaList` in the functions list + // Don't include the spoofed `VaListImpl` in the functions list // of inputs. &sig.inputs()[..sig.inputs().len() - 1] } else { diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ac5efa46406..16dfb161a54 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1695,7 +1695,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { from_hir_call: bool, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); - // Do not count the `VaList` argument as a "true" argument to + // Do not count the `VaListImpl` argument as a "true" argument to // a C-variadic function. let inputs = if sig.c_variadic { &sig.inputs()[..sig.inputs().len() - 1] diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7f690b6e828..8c2b8d1565f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -83,12 +83,15 @@ pub fn check_intrinsic_type<'tcx>(tcx: TyCtxt<'tcx>, it: &hir::ForeignItem) { let param = |n| tcx.mk_ty_param(n, InternedString::intern(&format!("P{}", n))); let name = it.ident.as_str(); - let mk_va_list_ty = || { + let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - tcx.mk_mut_ref(tcx.mk_region(env_region), va_list_ty) + (tcx.mk_ref(tcx.mk_region(env_region), ty::TypeAndMut { + ty: va_list_ty, + mutbl + }), va_list_ty) }) }; @@ -340,42 +343,25 @@ pub fn check_intrinsic_type<'tcx>(tcx: TyCtxt<'tcx>, it: &hir::ForeignItem) { } "va_start" | "va_end" => { - match mk_va_list_ty() { - Some(va_list_ty) => (0, vec![va_list_ty], tcx.mk_unit()), + match mk_va_list_ty(hir::MutMutable) { + Some((va_list_ref_ty, _)) => (0, vec![va_list_ref_ty], tcx.mk_unit()), None => bug!("`va_list` language item needed for C-variadic intrinsics") } } "va_copy" => { - match tcx.lang_items().va_list() { - Some(did) => { - let region = tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(0))); - let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); - let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); - let ret_ty = match va_list_ty.sty { - ty::Adt(def, _) if def.is_struct() => { - let fields = &def.non_enum_variant().fields; - match tcx.type_of(fields[0].did).subst(tcx, &[region.into()]).sty { - ty::Ref(_, element_ty, _) => match element_ty.sty { - ty::Adt(..) => element_ty, - _ => va_list_ty - } - _ => bug!("va_list structure is invalid") - } - } - _ => { - bug!("va_list structure is invalid") - } - }; - (0, vec![tcx.mk_imm_ref(tcx.mk_region(env_region), va_list_ty)], ret_ty) + match mk_va_list_ty(hir::MutImmutable) { + Some((va_list_ref_ty, va_list_ty)) => { + let va_list_ptr_ty = tcx.mk_mut_ptr(va_list_ty); + (0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.mk_unit()) } None => bug!("`va_list` language item needed for C-variadic intrinsics") } } "va_arg" => { - match mk_va_list_ty() { - Some(va_list_ty) => (1, vec![va_list_ty], param(0)), + match mk_va_list_ty(hir::MutMutable) { + Some((va_list_ref_ty, _)) => (1, vec![va_list_ref_ty], param(0)), None => bug!("`va_list` language item needed for C-variadic intrinsics") } } diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 7a38f0ebd5a..69fcfa8b39c 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -170,7 +170,7 @@ pub use core::ffi::c_void; reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", issue = "44930")] -pub use core::ffi::VaList; +pub use core::ffi::{VaList, VaListImpl}; mod c_str; mod os_str; diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index 27a26d244c2..7f2afd9c571 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -216,20 +216,27 @@ uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) { } // Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs -// passed as variadic arguments. -double rust_interesting_average(uint64_t n, ...) { - va_list pairs; +// passed as variadic arguments. There are two versions of this function: the +// variadic one, and the one that takes a `va_list`. +double rust_valist_interesting_average(uint64_t n, va_list pairs) { double sum = 0.0; int i; - va_start(pairs, n); for(i = 0; i < n; i += 1) { sum += (double)va_arg(pairs, int64_t); sum += va_arg(pairs, double); } - va_end(pairs); return sum / n; } +double rust_interesting_average(uint64_t n, ...) { + double sum; + va_list pairs; + va_start(pairs, n); + sum = rust_valist_interesting_average(n, pairs); + va_end(pairs); + return sum; +} + int32_t rust_int8_to_int32(int8_t x) { return (int32_t)x; } diff --git a/src/test/codegen/c-variadic-copy.rs b/src/test/codegen/c-variadic-copy.rs new file mode 100644 index 00000000000..4c61c4fcf68 --- /dev/null +++ b/src/test/codegen/c-variadic-copy.rs @@ -0,0 +1,16 @@ +// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy` + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +extern "C" { + fn foreign_c_variadic_1(_: VaList, ...); +} + +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); +} diff --git a/src/test/codegen/c-variadic-opt.rs b/src/test/codegen/c-variadic-opt.rs index 8594d309b0a..969dce80f58 100644 --- a/src/test/codegen/c-variadic-opt.rs +++ b/src/test/codegen/c-variadic-opt.rs @@ -10,10 +10,21 @@ extern "C" { } // Ensure that `va_start` and `va_end` are properly injected even -// when the "spoofed" `VaList` is not used. +// when the "spoofed" `VaListImpl` 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) + vprintf(fmt, ap.as_va_list()) + // CHECK: call void @llvm.va_end +} + +// Check that `VaListImpl::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()); + res // CHECK: call void @llvm.va_end } diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs index 09c18ed90b2..13be5ced27f 100644 --- a/src/test/codegen/c-variadic.rs +++ b/src/test/codegen/c-variadic.rs @@ -23,7 +23,7 @@ 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" `VaList` that is used by Rust defined C-variadics. +// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics. pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap) foreign_c_variadic_1(ap); diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs index 163d50c4e4b..a0a5b141ec0 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs @@ -88,6 +88,6 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { } #[no_mangle] -pub unsafe extern "C" fn check_varargs_2(_: c_int, mut ap: ...) -> usize { +pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index 3539c8d6b72..d6fbb1773b2 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -1,8 +1,45 @@ // ignore-wasm32-bare no libc to test ffi with +#![feature(c_variadic)] + +use std::ffi::VaList; #[link(name = "rust_test_helpers", kind = "static")] extern { fn rust_interesting_average(_: u64, ...) -> f64; + + // FIXME: we need to disable this lint for `VaList`, + // since it contains a `MaybeUninit` on the asmjs target, + // and this type isn't FFI-safe. This is OK for now, + // since the type is layout-compatible with `i32`. + #[cfg_attr(target_arch = "asmjs", allow(improper_ctypes))] + 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_va_copy(_: u64, mut ap: ...) { + let mut ap2 = ap.clone(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 30); + + // Advance one pair in the copy before checking + let mut ap2 = ap.clone(); + let _ = ap2.arg::(); + let _ = ap2.arg::(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) 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 mut ap2 = ap.clone(); + let _ = ap2.arg::(); + let _ = ap2.arg::(); + assert_eq!(rust_valist_interesting_average(2, ap2.as_va_list()) as i64, 70); } pub fn main() { @@ -35,4 +72,12 @@ pub fn main() { let x: unsafe extern fn(u64, ...) -> f64 = rust_interesting_average; call(x); } + + unsafe { + assert_eq!(test_valist_forward(2, 10i64, 10f64, 20i64, 20f64) as i64, 30); + } + + unsafe { + test_va_copy(4, 10i64, 10f64, 20i64, 20f64, 30i64, 30f64, 40i64, 40f64); + } } diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index e16d15a98bf..695eba2a7ee 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -29,7 +29,7 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; | ^^^ expected non-variadic fn, found variadic function | = note: expected type `unsafe extern "C" fn(isize, u8)` - found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...) {foo}` + found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...) {foo}` error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:20:54 @@ -37,7 +37,7 @@ error[E0308]: mismatched types LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; | ^^^ expected variadic fn, found non-variadic function | - = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...)` + = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaListImpl<'r>, ...)` found type `extern "C" fn(isize, u8) {bar}` error[E0617]: can't pass `f32` to variadic function diff --git a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr index a1afbb06390..3c5131835b5 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.nll.stderr @@ -1,16 +1,16 @@ error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { - | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` LL | ap - | ^^ lifetime `'a` required + | ^^ lifetime `'f` required error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:12:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` LL | ap | ^^ lifetime `'static` required @@ -20,43 +20,43 @@ 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 core::ffi::VaList<'2> - | has type `core::ffi::VaList<'1>` + | | return type of closure is core::ffi::VaList<'2, '_> + | has type `core::ffi::VaList<'1, '_>` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:20:5 | -LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaList<'1>` +LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'1>` | | - | has type `&mut core::ffi::VaList<'2>` + | has type `&mut core::ffi::VaListImpl<'2>` LL | *ap0 = ap1; - | ^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + | ^^^^ assignment requires that `'1` must outlive `'2` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:24:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { - | --- ------- has type `core::ffi::VaList<'2>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | --- ------- has type `core::ffi::VaListImpl<'2>` | | - | has type `&mut core::ffi::VaList<'1>` + | has type `&mut core::ffi::VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:24:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { - | --- ------- has type `core::ffi::VaList<'1>` +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { + | --- ------- has type `core::ffi::VaListImpl<'1>` | | - | has type `&mut core::ffi::VaList<'2>` + | has type `&mut core::ffi::VaListImpl<'2>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` error[E0384]: cannot assign to immutable argument `ap0` --> $DIR/variadic-ffi-4.rs:24:5 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { | --- help: make this binding mutable: `mut ap0` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ cannot assign to immutable argument @@ -64,7 +64,7 @@ LL | ap0 = &mut ap1; error[E0597]: `ap1` does not live long enough --> $DIR/variadic-ffi-4.rs:24:11 | -LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { | - let's call the lifetime of this reference `'1` LL | ap0 = &mut ap1; | ------^^^^^^^^ @@ -73,9 +73,19 @@ LL | ap0 = &mut ap1; | assignment requires that `ap1` is borrowed for `'1` ... LL | } - | - `ap1` dropped here while still borrowed + | - `ap1` dropped here while still borrowed -error: aborting due to 8 previous errors +error: lifetime may not live long enough + --> $DIR/variadic-ffi-4.rs:32:5 + | +LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaListImpl<'1>` + | | + | has type `&mut core::ffi::VaListImpl<'2>` +LL | *ap0 = ap1.clone(); + | ^^^^ assignment requires that `'1` must outlive `'2` + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0384, E0597, E0621. For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs index 1c77479d02f..07c32ecbfc2 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.rs +++ b/src/test/ui/c-variadic/variadic-ffi-4.rs @@ -2,13 +2,13 @@ #![no_std] #![feature(c_variadic)] -use core::ffi::VaList; +use core::ffi::{VaList, VaListImpl}; -pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { +pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { ap //~ ERROR: explicit lifetime required } -pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { ap //~ ERROR: explicit lifetime required } @@ -16,14 +16,18 @@ pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { let _ = ap.with_copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime } -pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { *ap0 = ap1; //~ ERROR: mismatched types } -pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { ap0 = &mut ap1; - //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long + //~^ ERROR: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long //~^^ ERROR: mismatched types //~^^^ ERROR: mismatched types //~^^^^ ERROR: cannot infer an appropriate lifetime } + +pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { + *ap0 = ap1.clone(); //~ ERROR: cannot infer an appropriate lifetime +} diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 80b765671c5..72d4d8b6344 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -1,16 +1,16 @@ error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:8:5 | -LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { - | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` +LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { + | --- help: add explicit lifetime `'f` to the type of `ap`: `core::ffi::VaListImpl<'f>` LL | ap - | ^^ lifetime `'a` required + | ^^ lifetime `'f` required error[E0621]: explicit lifetime required in the type of `ap` --> $DIR/variadic-ffi-4.rs:12:5 | -LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { - | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaListImpl<'static>` LL | ap | ^^ lifetime `'static` required @@ -26,14 +26,14 @@ note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on th LL | let _ = ap.with_copy(|ap| { ap }); | ^^^^^^^^^^^ = note: ...so that the expression is assignable: - expected core::ffi::VaList<'_> - found core::ffi::VaList<'_> + expected core::ffi::VaList<'_, '_> + found core::ffi::VaList<'_, '_> note: but, the lifetime must be valid for the method call at 16:13... --> $DIR/variadic-ffi-4.rs:16:13 | LL | let _ = ap.with_copy(|ap| { ap }); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so type `core::ffi::VaList<'_>` of expression is valid during the expression +note: ...so type `core::ffi::VaList<'_, '_>` of expression is valid during the expression --> $DIR/variadic-ffi-4.rs:16:13 | LL | let _ = ap.with_copy(|ap| { ap }); @@ -45,24 +45,24 @@ error[E0308]: mismatched types LL | *ap0 = ap1; | ^^^ lifetime mismatch | - = note: expected type `core::ffi::VaList<'_>` - found type `core::ffi::VaList<'_>` + = note: expected type `core::ffi::VaListImpl<'_>` + found type `core::ffi::VaListImpl<'_>` note: the anonymous lifetime #3 defined on the function body at 19:1... --> $DIR/variadic-ffi-4.rs:19:1 | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { LL | | *ap0 = ap1; LL | | } | |_^ note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1 --> $DIR/variadic-ffi-4.rs:19:1 | -LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { LL | | *ap0 = ap1; LL | | } | |_^ -error[E0490]: a value of type `core::ffi::VaList<'_>` is borrowed for too long +error[E0490]: a value of type `core::ffi::VaListImpl<'_>` is borrowed for too long --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; @@ -71,7 +71,7 @@ LL | ap0 = &mut ap1; note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -82,7 +82,7 @@ LL | | } note: but the borrow lasts for the anonymous lifetime #3 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -97,12 +97,12 @@ error[E0308]: mismatched types LL | ap0 = &mut ap1; | ^^^^^^^^ lifetime mismatch | - = note: expected type `&mut core::ffi::VaList<'_>` - found type `&mut core::ffi::VaList<'_>` + = note: expected type `&mut core::ffi::VaListImpl<'_>` + found type `&mut core::ffi::VaListImpl<'_>` note: the anonymous lifetime #3 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -113,7 +113,7 @@ LL | | } note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -128,12 +128,12 @@ error[E0308]: mismatched types LL | ap0 = &mut ap1; | ^^^^^^^^ lifetime mismatch | - = note: expected type `&mut core::ffi::VaList<'_>` - found type `&mut core::ffi::VaList<'_>` + = note: expected type `&mut core::ffi::VaListImpl<'_>` + found type `&mut core::ffi::VaListImpl<'_>` note: the anonymous lifetime #2 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -144,7 +144,7 @@ LL | | } note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 23:1 --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -162,7 +162,7 @@ LL | ap0 = &mut ap1; note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -170,7 +170,7 @@ LL | | LL | | LL | | } | |_^ -note: ...so that the type `core::ffi::VaList<'_>` is not borrowed for too long +note: ...so that the type `core::ffi::VaListImpl<'_>` is not borrowed for too long --> $DIR/variadic-ffi-4.rs:24:11 | LL | ap0 = &mut ap1; @@ -178,7 +178,7 @@ LL | ap0 = &mut ap1; note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1... --> $DIR/variadic-ffi-4.rs:23:1 | -LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaListImpl, mut ap1: ...) { LL | | ap0 = &mut ap1; LL | | LL | | @@ -192,7 +192,34 @@ note: ...so that reference does not outlive borrowed content LL | ap0 = &mut ap1; | ^^^^^^^^ -error: aborting due to 8 previous errors +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/variadic-ffi-4.rs:32:16 + | +LL | *ap0 = ap1.clone(); + | ^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 31:1... + --> $DIR/variadic-ffi-4.rs:31:1 + | +LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1.clone(); +LL | | } + | |_^ + = note: ...so that the types are compatible: + expected &core::ffi::VaListImpl<'_> + found &core::ffi::VaListImpl<'_> +note: but, the lifetime must be valid for the anonymous lifetime #2 defined on the function body at 31:1... + --> $DIR/variadic-ffi-4.rs:31:1 + | +LL | / pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { +LL | | *ap0 = ap1.clone(); +LL | | } + | |_^ + = note: ...so that the expression is assignable: + expected core::ffi::VaListImpl<'_> + found core::ffi::VaListImpl<'_> + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0621. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/error-codes/E0617.rs b/src/test/ui/error-codes/E0617.rs index 51f13c7dbd5..439c3db5768 100644 --- a/src/test/ui/error-codes/E0617.rs +++ b/src/test/ui/error-codes/E0617.rs @@ -22,7 +22,7 @@ fn main() { //~^ ERROR can't pass `u16` to variadic function //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), printf); - //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function - //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` + //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function + //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` } } diff --git a/src/test/ui/error-codes/E0617.stderr b/src/test/ui/error-codes/E0617.stderr index 8387d5c7e93..d866320bbcd 100644 --- a/src/test/ui/error-codes/E0617.stderr +++ b/src/test/ui/error-codes/E0617.stderr @@ -28,15 +28,15 @@ error[E0617]: can't pass `u16` to variadic function LL | printf(::std::ptr::null(), 0u16); | ^^^^ help: cast the value to `c_uint`: `0u16 as c_uint` -error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function +error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...) {printf}` to variadic function --> $DIR/E0617.rs:24:36 | LL | printf(::std::ptr::null(), printf); | ^^^^^^ -help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` +help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)` | -LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaListImpl<'r>, ...)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 9ed93bb9818..52bb118fa23 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -57,7 +57,7 @@ fn main() { } // Test type mangling, by putting them in an `impl` header. - // FIXME(eddyb) test C varargs when `core::ffi::VaList` stops leaking into the signature + // FIXME(eddyb) test C varargs when `core::ffi::VaListImpl` stops leaking into the signature // (which is a problem because `core` has an unpredictable hash) - see also #44930. impl Bar for [&'_ (dyn Foo + AutoTrait); 3] { #[rustc_symbol_name]