1
Fork 0

Rollup merge of #115654 - RalfJung:pass-mode-cast, r=compiler-errors

improve PassMode docs
This commit is contained in:
Dylan DPC 2023-09-17 11:23:25 +00:00 committed by GitHub
commit 0c5f5b6db7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 118 additions and 96 deletions

View file

@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
} }
_ => unreachable!("{:?}", self.layout.abi), _ => unreachable!("{:?}", self.layout.abi),
}, },
PassMode::Cast(ref cast, pad_i32) => { PassMode::Cast { ref cast, pad_i32 } => {
assert!(!pad_i32, "padding support not yet implemented"); assert!(!pad_i32, "padding support not yet implemented");
cast_target_to_abi_params(cast) cast_target_to_abi_params(cast)
} }
PassMode::Indirect { attrs, extra_attrs: None, on_stack } => { PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
if on_stack { if on_stack {
// Abi requires aligning struct size to pointer size // Abi requires aligning struct size to pointer size
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
@ -117,11 +117,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
} }
} }
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => { PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack); assert!(!on_stack);
smallvec![ smallvec![
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs), apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
] ]
} }
} }
@ -148,14 +148,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
} }
_ => unreachable!("{:?}", self.layout.abi), _ => unreachable!("{:?}", self.layout.abi),
}, },
PassMode::Cast(ref cast, _) => { PassMode::Cast { ref cast, .. } => {
(None, cast_target_to_abi_params(cast).into_iter().collect()) (None, cast_target_to_abi_params(cast).into_iter().collect())
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
assert!(!on_stack); assert!(!on_stack);
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
} }
@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
let (a, b) = arg.load_scalar_pair(fx); let (a, b) = arg.load_scalar_pair(fx);
smallvec![a, b] smallvec![a, b]
} }
PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast), PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
if is_owned { if is_owned {
match arg.force_stack(fx) { match arg.force_stack(fx) {
@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>(
assert_eq!(block_params.len(), 2, "{:?}", block_params); assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
} }
PassMode::Cast(ref cast, _) => { PassMode::Cast { ref cast, .. } => {
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
assert_eq!(block_params.len(), 1, "{:?}", block_params); assert_eq!(block_params.len(), 1, "{:?}", block_params);
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)) Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
assert_eq!(block_params.len(), 2, "{:?}", block_params); assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_ref_unsized( Some(CValue::by_ref_unsized(
Pointer::new(block_params[0]), Pointer::new(block_params[0]),

View file

@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
block_params_iter: &mut impl Iterator<Item = Value>, block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> { ) -> CPlace<'tcx> {
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => { PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => {
let is_ssa = let is_ssa =
ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty); ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
( (
@ -26,7 +26,7 @@ pub(super) fn codegen_return_param<'tcx>(
smallvec![], smallvec![],
) )
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
let ret_param = block_params_iter.next().unwrap(); let ret_param = block_params_iter.next().unwrap();
assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type); assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
( (
@ -34,7 +34,7 @@ pub(super) fn codegen_return_param<'tcx>(
smallvec![ret_param], smallvec![ret_param],
) )
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
}; };
@ -62,7 +62,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
) { ) {
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
PassMode::Ignore => (None, None), PassMode::Ignore => (None, None),
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
if let Some(ret_ptr) = ret_place.try_to_ptr() { if let Some(ret_ptr) = ret_place.try_to_ptr() {
// This is an optimization to prevent unnecessary copies of the return value when // This is an optimization to prevent unnecessary copies of the return value when
// the return place is already a memory place as opposed to a register. // the return place is already a memory place as opposed to a register.
@ -73,10 +73,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
(Some(place), Some(place.to_ptr().get_addr(fx))) (Some(place), Some(place.to_ptr().get_addr(fx)))
} }
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None), PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None),
}; };
let call_inst = f(fx, return_ptr); let call_inst = f(fx, return_ptr);
@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
ret_place ret_place
.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
} }
PassMode::Cast(ref cast, _) => { PassMode::Cast { ref cast, .. } => {
let results = let results =
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>(); fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
let result = let result =
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
ret_place.write_cvalue(fx, result); ret_place.write_cvalue(fx, result);
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
if let Some(ret_temp_place) = ret_temp_place { if let Some(ret_temp_place) = ret_temp_place {
// If ret_temp_place is None, it is not necessary to copy the return value. // If ret_temp_place is None, it is not necessary to copy the return value.
let ret_temp_value = ret_temp_place.to_cvalue(fx); let ret_temp_value = ret_temp_place.to_cvalue(fx);
ret_place.write_cvalue(fx, ret_temp_value); ret_place.write_cvalue(fx, ret_temp_value);
} }
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
} }
@ -116,10 +116,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
/// Codegen a return instruction with the right return value(s) if any. /// Codegen a return instruction with the right return value(s) if any.
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
match fx.fn_abi.as_ref().unwrap().ret.mode { match fx.fn_abi.as_ref().unwrap().ret.mode {
PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
fx.bcx.ins().return_(&[]); fx.bcx.ins().return_(&[]);
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value") unreachable!("unsized return value")
} }
PassMode::Direct(_) => { PassMode::Direct(_) => {
@ -132,7 +132,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
} }
PassMode::Cast(ref cast, _) => { PassMode::Cast { ref cast, .. } => {
let place = fx.get_local_place(RETURN_PLACE); let place = fx.get_local_place(RETURN_PLACE);
let ret_val = place.to_cvalue(fx); let ret_val = place.to_cvalue(fx);
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast); let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);

View file

@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
match self.ret.mode { match self.ret.mode {
PassMode::Ignore => cx.type_void(), PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
PassMode::Cast(ref cast, _) => cast.gcc_type(cx), PassMode::Cast { ref cast, .. } => cast.gcc_type(cx),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void() cx.type_void()
@ -129,21 +129,21 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1)); argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
continue; continue;
} }
PassMode::Indirect { extra_attrs: Some(_), .. } => { PassMode::Indirect { meta_attrs: Some(_), .. } => {
unimplemented!(); unimplemented!();
} }
PassMode::Cast(ref cast, pad_i32) => { PassMode::Cast { ref cast, pad_i32 } => {
// add padding // add padding
if pad_i32 { if pad_i32 {
argument_tys.push(Reg::i32().gcc_type(cx)); argument_tys.push(Reg::i32().gcc_type(cx));
} }
cast.gcc_type(cx) cast.gcc_type(cx)
} }
PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => {
on_stack_param_indices.insert(argument_tys.len()); on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx) arg.memory_ty(cx)
}, },
PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)), PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
}; };
argument_tys.push(arg_ty); argument_tys.push(arg_ty);
} }

View file

@ -144,7 +144,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => { sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0); let tp_ty = fn_args.type_at(0);
let mut ptr = args[0].immediate(); let mut ptr = args[0].immediate();
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
} }
let load = self.volatile_load(ptr.get_type(), ptr); let load = self.volatile_load(ptr.get_type(), ptr);
@ -353,7 +353,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
let ptr = self.pointercast(result.llval, ptr_llty); let ptr = self.pointercast(result.llval, ptr_llty);
self.store(llval, ptr, result.align); self.store(llval, ptr, result.align);
@ -449,7 +449,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
else if self.is_unsized_indirect() { else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} }
else if let PassMode::Cast(ref cast, _) = self.mode { else if let PassMode::Cast { ref cast, .. } = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang // FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false; let can_store_through_cast_ptr = false;
@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Pair(..) => { PassMode::Pair(..) => {
OperandValue::Pair(next(), next()).store(bx, dst); OperandValue::Pair(next(), next()).store(bx, dst);
}, },
PassMode::Indirect { extra_attrs: Some(_), .. } => { PassMode::Indirect { meta_attrs: Some(_), .. } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
}, },
PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => { PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => {
let next_arg = next(); let next_arg = next();
self.store(bx, next_arg, dst); self.store(bx, next_arg, dst);
}, },

View file

@ -211,7 +211,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
} else if self.is_unsized_indirect() { } else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} else if let PassMode::Cast(cast, _) = &self.mode { } else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang // FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false; let can_store_through_cast_ptr = false;
@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Pair(..) => { PassMode::Pair(..) => {
OperandValue::Pair(next(), next()).store(bx, dst); OperandValue::Pair(next(), next()).store(bx, dst);
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
} }
PassMode::Direct(_) PassMode::Direct(_)
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
| PassMode::Cast(..) => { | PassMode::Cast { .. } => {
let next_arg = next(); let next_arg = next();
self.store(bx, next_arg, dst); self.store(bx, next_arg, dst);
} }
@ -332,7 +332,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let llreturn_ty = match &self.ret.mode { let llreturn_ty = match &self.ret.mode {
PassMode::Ignore => cx.type_void(), PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
PassMode::Cast(cast, _) => cast.llvm_type(cx), PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx),
PassMode::Indirect { .. } => { PassMode::Indirect { .. } => {
llargument_tys.push(cx.type_ptr()); llargument_tys.push(cx.type_ptr());
cx.type_void() cx.type_void()
@ -351,6 +351,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
// aggregates... // aggregates...
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) { if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
assert!(
arg.layout.is_sized(),
"`PassMode::Direct` for unsized type: {}",
arg.layout.ty
);
// This really shouldn't happen, since `immediate_llvm_type` will use // This really shouldn't happen, since `immediate_llvm_type` will use
// `layout.fields` to turn this Rust type into an LLVM type. This means all // `layout.fields` to turn this Rust type into an LLVM type. This means all
// sorts of Rust type details leak into the ABI. However wasm sadly *does* // sorts of Rust type details leak into the ABI. However wasm sadly *does*
@ -378,8 +383,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
continue; continue;
} }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
assert!(arg.layout.is_unsized()); // `Indirect` with metadata is only for unsized types, and doesn't work with
// on-stack passing.
assert!(arg.layout.is_unsized() && !on_stack);
// Construct the type of a (wide) pointer to `ty`, and pass its two fields. // Construct the type of a (wide) pointer to `ty`, and pass its two fields.
// Any two ABI-compatible unsized types have the same metadata type and // Any two ABI-compatible unsized types have the same metadata type and
// moreover the same metadata value leads to the same dynamic size and // moreover the same metadata value leads to the same dynamic size and
@ -390,7 +397,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
continue; continue;
} }
PassMode::Cast(cast, pad_i32) => { PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
assert!(arg.layout.is_sized());
cx.type_ptr()
}
PassMode::Cast { cast, pad_i32 } => {
// `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
assert!(arg.layout.is_sized());
// add padding // add padding
if *pad_i32 { if *pad_i32 {
llargument_tys.push(Reg::i32().llvm_type(cx)); llargument_tys.push(Reg::i32().llvm_type(cx));
@ -399,7 +412,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
// We assume here that ABI-compatible Rust types have the same cast type. // We assume here that ABI-compatible Rust types have the same cast type.
cast.llvm_type(cx) cast.llvm_type(cx)
} }
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
}; };
llargument_tys.push(llarg_ty); llargument_tys.push(llarg_ty);
} }
@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Direct(attrs) => { PassMode::Direct(attrs) => {
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
} }
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
assert!(!on_stack); assert!(!on_stack);
let i = apply(attrs); let i = apply(attrs);
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx)); let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
} }
PassMode::Cast(cast, _) => { PassMode::Cast { cast, pad_i32: _ } => {
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
} }
_ => {} _ => {}
@ -456,25 +468,25 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
for arg in self.args.iter() { for arg in self.args.iter() {
match &arg.mode { match &arg.mode {
PassMode::Ignore => {} PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
let i = apply(attrs); let i = apply(attrs);
let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx)); let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
} }
PassMode::Direct(attrs) PassMode::Direct(attrs)
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply(attrs); apply(attrs);
} }
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => { PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack); assert!(!on_stack);
apply(attrs); apply(attrs);
apply(extra_attrs); apply(meta_attrs);
} }
PassMode::Pair(a, b) => { PassMode::Pair(a, b) => {
apply(a); apply(a);
apply(b); apply(b);
} }
PassMode::Cast(cast, pad_i32) => { PassMode::Cast { cast, pad_i32 } => {
if *pad_i32 { if *pad_i32 {
apply(&ArgAttributes::new()); apply(&ArgAttributes::new());
} }
@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Direct(attrs) => { PassMode::Direct(attrs) => {
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
} }
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
assert!(!on_stack); assert!(!on_stack);
let i = apply(bx.cx, attrs); let i = apply(bx.cx, attrs);
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx)); let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
} }
PassMode::Cast(cast, _) => { PassMode::Cast { cast, pad_i32: _ } => {
cast.attrs.apply_attrs_to_callsite( cast.attrs.apply_attrs_to_callsite(
llvm::AttributePlace::ReturnValue, llvm::AttributePlace::ReturnValue,
&bx.cx, &bx.cx,
@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
for arg in self.args.iter() { for arg in self.args.iter() {
match &arg.mode { match &arg.mode {
PassMode::Ignore => {} PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
let i = apply(bx.cx, attrs); let i = apply(bx.cx, attrs);
let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx)); let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
attributes::apply_to_callsite( attributes::apply_to_callsite(
@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
); );
} }
PassMode::Direct(attrs) PassMode::Direct(attrs)
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply(bx.cx, attrs); apply(bx.cx, attrs);
} }
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => { PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack: _ } => {
apply(bx.cx, attrs); apply(bx.cx, attrs);
apply(bx.cx, extra_attrs); apply(bx.cx, meta_attrs);
} }
PassMode::Pair(a, b) => { PassMode::Pair(a, b) => {
apply(bx.cx, a); apply(bx.cx, a);
apply(bx.cx, b); apply(bx.cx, b);
} }
PassMode::Cast(cast, pad_i32) => { PassMode::Cast { cast, pad_i32 } => {
if *pad_i32 { if *pad_i32 {
apply(bx.cx, &ArgAttributes::new()); apply(bx.cx, &ArgAttributes::new());
} }

View file

@ -165,7 +165,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => { sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0); let tp_ty = fn_args.type_at(0);
let ptr = args[0].immediate(); let ptr = args[0].immediate();
let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
let llty = ty.llvm_type(self); let llty = ty.llvm_type(self);
self.volatile_load(llty, ptr) self.volatile_load(llty, ptr)
} else { } else {
@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(_, _) = &fn_abi.ret.mode { if let PassMode::Cast { .. } = &fn_abi.ret.mode {
self.store(llval, result.llval, result.align); self.store(llval, result.llval, result.align);
} else { } else {
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)

View file

@ -416,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
} }
PassMode::Cast(cast_ty, _) => { PassMode::Cast { cast: cast_ty, pad_i32: _ } => {
let op = match self.locals[mir::RETURN_PLACE] { let op = match self.locals[mir::RETURN_PLACE] {
LocalRef::Operand(op) => op, LocalRef::Operand(op) => op,
LocalRef::PendingOperand => bug!("use of return before def"), LocalRef::PendingOperand => bug!("use of return before def"),
@ -1310,7 +1310,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) { ) {
match arg.mode { match arg.mode {
PassMode::Ignore => return, PassMode::Ignore => return,
PassMode::Cast(_, true) => { PassMode::Cast { pad_i32: true, .. } => {
// Fill padding with undef value, where applicable. // Fill padding with undef value, where applicable.
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32()))); llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
} }
@ -1322,7 +1322,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
_ => bug!("codegen_argument: {:?} invalid for pair argument", op), _ => bug!("codegen_argument: {:?} invalid for pair argument", op),
}, },
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val { PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val {
Ref(a, Some(b), _) => { Ref(a, Some(b), _) => {
llargs.push(a); llargs.push(a);
llargs.push(b); llargs.push(b);
@ -1347,7 +1347,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
op.val.store(bx, scratch); op.val.store(bx, scratch);
(scratch.llval, scratch.align, true) (scratch.llval, scratch.align, true)
} }
PassMode::Cast(..) => { PassMode::Cast { .. } => {
let scratch = PlaceRef::alloca(bx, arg.layout); let scratch = PlaceRef::alloca(bx, arg.layout);
op.val.store(bx, scratch); op.val.store(bx, scratch);
(scratch.llval, scratch.align, true) (scratch.llval, scratch.align, true)
@ -1400,7 +1400,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if by_ref && !arg.is_indirect() { if by_ref && !arg.is_indirect() {
// Have to load the argument, maybe while casting it. // Have to load the argument, maybe while casting it.
if let PassMode::Cast(ty, _) = &arg.mode { if let PassMode::Cast { cast: ty, .. } = &arg.mode {
let llty = bx.cast_backend_type(ty); let llty = bx.cast_backend_type(ty);
llval = bx.load(llty, llval, align.min(arg.layout.align.abi)); llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
} else { } else {
@ -1744,7 +1744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
DirectOperand(index) => { DirectOperand(index) => {
// If there is a cast, we have to store and reload. // If there is a cast, we have to store and reload.
let op = if let PassMode::Cast(..) = ret_abi.mode { let op = if let PassMode::Cast { .. } = ret_abi.mode {
let tmp = PlaceRef::alloca(bx, ret_abi.layout); let tmp = PlaceRef::alloca(bx, ret_abi.layout);
tmp.storage_live(bx); tmp.storage_live(bx);
bx.store_arg(&ret_abi, llval, tmp); bx.store_arg(&ret_abi, llval, tmp);

View file

@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(..) = &fn_abi.ret.mode { if let PassMode::Cast { .. } = &fn_abi.ret.mode {
bx.store(llval, result.llval, result.align); bx.store(llval, result.llval, result.align);
} else { } else {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)

View file

@ -327,7 +327,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
for i in 0..tupled_arg_tys.len() { for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_abi.args[idx]; let arg = &fx.fn_abi.args[idx];
idx += 1; idx += 1;
if let PassMode::Cast(_, true) = arg.mode { if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
llarg_idx += 1; llarg_idx += 1;
} }
let pr_field = place.project_field(bx, i); let pr_field = place.project_field(bx, i);
@ -351,7 +351,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let arg = &fx.fn_abi.args[idx]; let arg = &fx.fn_abi.args[idx];
idx += 1; idx += 1;
if let PassMode::Cast(_, true) = arg.mode { if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
llarg_idx += 1; llarg_idx += 1;
} }

View file

@ -46,17 +46,17 @@ pub enum PassMode {
/// ///
/// The argument has a layout abi of `ScalarPair`. /// The argument has a layout abi of `ScalarPair`.
Pair(ArgAttributes, ArgAttributes), Pair(ArgAttributes, ArgAttributes),
/// Pass the argument after casting it, to either a single uniform or a /// Pass the argument after casting it. See the `CastTarget` docs for details. The bool
/// pair of registers. The bool indicates if a `Reg::i32()` dummy argument /// indicates if a `Reg::i32()` dummy argument is emitted before the real argument.
/// is emitted before the real argument. Cast { pad_i32: bool, cast: Box<CastTarget> },
Cast(Box<CastTarget>, bool),
/// Pass the argument indirectly via a hidden pointer. /// Pass the argument indirectly via a hidden pointer.
/// The `extra_attrs` value, if any, is for the extra data (vtable or length) /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized
/// which indicates that it refers to an unsized rvalue. /// argument. (This is the only mode that supports unsized arguments.)
/// `on_stack` defines that the value should be passed at a fixed /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to
/// stack offset in accordance to the ABI rather than passed using a /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument
/// pointer. This corresponds to the `byval` LLVM argument attribute. /// attribute (using the Rust type of this argument). `on_stack` cannot be true for unsized
Indirect { attrs: ArgAttributes, extra_attrs: Option<ArgAttributes>, on_stack: bool }, /// arguments, i.e., when `meta_attrs` is `Some`.
Indirect { attrs: ArgAttributes, meta_attrs: Option<ArgAttributes>, on_stack: bool },
} }
impl PassMode { impl PassMode {
@ -65,17 +65,20 @@ impl PassMode {
/// so that needs to be compared as well! /// so that needs to be compared as well!
pub fn eq_abi(&self, other: &Self) -> bool { pub fn eq_abi(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type (PassMode::Ignore, PassMode::Ignore) => true,
(PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2), (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2),
(PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2), (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2),
(PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1.eq_abi(c2) && pad1 == pad2,
( (
PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, PassMode::Cast { cast: c1, pad_i32: pad1 },
PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, PassMode::Cast { cast: c2, pad_i32: pad2 },
) => c1.eq_abi(c2) && pad1 == pad2,
(
PassMode::Indirect { attrs: a1, meta_attrs: None, on_stack: s1 },
PassMode::Indirect { attrs: a2, meta_attrs: None, on_stack: s2 },
) => a1.eq_abi(a2) && s1 == s2, ) => a1.eq_abi(a2) && s1 == s2,
( (
PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 }, PassMode::Indirect { attrs: a1, meta_attrs: Some(e1), on_stack: s1 },
PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 }, PassMode::Indirect { attrs: a2, meta_attrs: Some(e2), on_stack: s2 },
) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2, ) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2,
_ => false, _ => false,
} }
@ -256,6 +259,13 @@ impl Uniform {
} }
} }
/// Describes the type used for `PassMode::Cast`.
///
/// Passing arguments in this mode works as follows: the registers in the `prefix` (the ones that
/// are `Some`) get laid out one after the other (using `repr(C)` layout rules). Then the
/// `rest.unit` register type gets repeated often enough to cover `rest.size`. This describes the
/// actual type used for the call; the Rust type of the argument is then transmuted to this ABI type
/// (and all data in the padding between the registers is dropped).
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget { pub struct CastTarget {
pub prefix: [Option<Reg>; 8], pub prefix: [Option<Reg>; 8],
@ -565,15 +575,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
attrs.pointee_size = layout.size; attrs.pointee_size = layout.size;
attrs.pointee_align = Some(layout.align.abi); attrs.pointee_align = Some(layout.align.abi);
let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new()); let meta_attrs = layout.is_unsized().then_some(ArgAttributes::new());
PassMode::Indirect { attrs, extra_attrs, on_stack: false } PassMode::Indirect { attrs, meta_attrs, on_stack: false }
} }
pub fn make_indirect(&mut self) { pub fn make_indirect(&mut self) {
match self.mode { match self.mode {
PassMode::Direct(_) | PassMode::Pair(_, _) => {} PassMode::Direct(_) | PassMode::Pair(_, _) => {}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return, PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: false } => return,
_ => panic!("Tried to make {:?} indirect", self.mode), _ => panic!("Tried to make {:?} indirect", self.mode),
} }
@ -583,7 +593,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) { pub fn make_indirect_byval(&mut self, byval_align: Option<Align>) {
self.make_indirect(); self.make_indirect();
match self.mode { match self.mode {
PassMode::Indirect { ref mut attrs, extra_attrs: _, ref mut on_stack } => { PassMode::Indirect { ref mut attrs, meta_attrs: _, ref mut on_stack } => {
*on_stack = true; *on_stack = true;
// Some platforms, like 32-bit x86, change the alignment of the type when passing // Some platforms, like 32-bit x86, change the alignment of the type when passing
@ -616,11 +626,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
} }
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
self.mode = PassMode::Cast(Box::new(target.into()), false); self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32: false };
} }
pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) { pub fn cast_to_and_pad_i32<T: Into<CastTarget>>(&mut self, target: T, pad_i32: bool) {
self.mode = PassMode::Cast(Box::new(target.into()), pad_i32); self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32 };
} }
pub fn is_indirect(&self) -> bool { pub fn is_indirect(&self) -> bool {
@ -628,11 +638,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
} }
pub fn is_sized_indirect(&self) -> bool { pub fn is_sized_indirect(&self) -> bool {
matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }) matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ })
} }
pub fn is_unsized_indirect(&self) -> bool { pub fn is_unsized_indirect(&self) -> bool {
matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }) matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ })
} }
pub fn is_ignore(&self) -> bool { pub fn is_ignore(&self) -> bool {

View file

@ -142,13 +142,13 @@ where
for arg in fn_abi.args.iter_mut() { for arg in fn_abi.args.iter_mut() {
let attrs = match arg.mode { let attrs = match arg.mode {
PassMode::Ignore PassMode::Ignore
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
continue; continue;
} }
PassMode::Direct(ref mut attrs) => attrs, PassMode::Direct(ref mut attrs) => attrs,
PassMode::Pair(..) PassMode::Pair(..)
| PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
| PassMode::Cast(..) => { | PassMode::Cast { .. } => {
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
} }
}; };

View file

@ -450,7 +450,7 @@ error: ABIs are not compatible
Align(1 bytes), Align(1 bytes),
), ),
}, },
extra_attrs: None, meta_attrs: None,
on_stack: false, on_stack: false,
}, },
}, },
@ -521,7 +521,7 @@ error: ABIs are not compatible
Align(4 bytes), Align(4 bytes),
), ),
}, },
extra_attrs: None, meta_attrs: None,
on_stack: false, on_stack: false,
}, },
}, },