mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #153398 - folkertdev:const-c-variadic-trailing-zst, r=RalfJung
fix ICE in `const_c_variadic` when passing ZSTs fixes https://github.com/rust-lang/rust/issues/153351 r? RalfJung There was a mismatch between the caller and callee ABI where the caller does not pass ZST arguments, but the callee does expect them. Because ZSTs don't implement `VaArgSafe` the program must already be invalid if this comes up.
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
|
||||
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi};
|
||||
use tracing::field::Empty;
|
||||
use tracing::{info, instrument, trace};
|
||||
|
||||
@@ -284,7 +284,7 @@ fn pass_argument<'x, 'y>(
|
||||
'tcx: 'y,
|
||||
{
|
||||
assert_eq!(callee_ty, callee_abi.layout.ty);
|
||||
if callee_abi.mode == PassMode::Ignore {
|
||||
if callee_abi.is_ignore() {
|
||||
// This one is skipped. Still must be made live though!
|
||||
if !already_live {
|
||||
self.storage_live(callee_arg.as_local().unwrap())?;
|
||||
@@ -450,7 +450,7 @@ pub fn init_stack_frame(
|
||||
let mut caller_args = args
|
||||
.iter()
|
||||
.zip(caller_fn_abi.args.iter())
|
||||
.filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
|
||||
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
|
||||
|
||||
// Now we have to spread them out across the callee's locals,
|
||||
// taking into account the `spread_arg`. If we could write
|
||||
@@ -480,7 +480,12 @@ pub fn init_stack_frame(
|
||||
|
||||
// Consume the remaining arguments by putting them into the variable argument
|
||||
// list.
|
||||
let varargs = self.allocate_varargs(&mut caller_args, &mut callee_args_abis)?;
|
||||
let varargs = self.allocate_varargs(
|
||||
&mut caller_args,
|
||||
// "Ignored" arguments aren't actually passed, so the callee should also
|
||||
// ignore them. (`pass_argument` does this for regular arguments.)
|
||||
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
|
||||
)?;
|
||||
// When the frame is dropped, these variable arguments are deallocated.
|
||||
self.frame_mut().va_list = varargs.clone();
|
||||
let key = self.va_list_ptr(varargs.into());
|
||||
|
||||
@@ -631,8 +631,8 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
||||
/// of variadic arguments. Return a list of the places that hold those arguments.
|
||||
pub(crate) fn allocate_varargs<I, J>(
|
||||
&mut self,
|
||||
caller_args: &mut I,
|
||||
callee_abis: &mut J,
|
||||
caller_args: I,
|
||||
mut callee_abis: J,
|
||||
) -> InterpResult<'tcx, Vec<MPlaceTy<'tcx, M::Provenance>>>
|
||||
where
|
||||
I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//@ ignore-target: windows # does not ignore ZST arguments
|
||||
//@ ignore-target: powerpc # does not ignore ZST arguments
|
||||
//@ ignore-target: s390x # does not ignore ZST arguments
|
||||
//@ ignore-target: sparc # does not ignore ZST arguments
|
||||
#![feature(c_variadic)]
|
||||
|
||||
// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part
|
||||
// of the callee's ABI. Test that this doesn't trip any asserts.
|
||||
//
|
||||
// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets,
|
||||
// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the
|
||||
// second `i32` argument while the next item in the variable argument list is `()`.
|
||||
|
||||
fn main() {
|
||||
unsafe extern "C" fn variadic(mut ap: ...) {
|
||||
ap.arg::<i32>();
|
||||
ap.arg::<i32>();
|
||||
}
|
||||
|
||||
unsafe { variadic(0i32, (), 1i32) }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//@ build-pass
|
||||
//@ compile-flags: --emit=obj
|
||||
#![feature(c_variadic)]
|
||||
#![feature(const_c_variadic)]
|
||||
#![feature(const_destruct)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Regression test for when a c-variadic argument is `PassMode::Ignore`. The caller won't pass the
|
||||
// argument, but the callee ABI does have the argument. Ensure that const-eval is able to handle
|
||||
// this case without tripping any asserts.
|
||||
|
||||
const unsafe extern "C" fn read_n<const N: usize>(_: ...) {}
|
||||
|
||||
unsafe fn read_too_many() {
|
||||
const { read_n::<0>((), 1i32) }
|
||||
}
|
||||
|
||||
fn read_as<T>() -> () {}
|
||||
Reference in New Issue
Block a user