Rollup merge of #144535 - RalfJung:abi-mismatch-err, r=compiler-errors

miri: for ABI mismatch errors, say which argument is the problem
This commit is contained in:
Matthias Krüger
2025-07-28 01:16:40 +02:00
committed by GitHub
25 changed files with 45 additions and 35 deletions

View File

@@ -128,15 +128,15 @@ const_eval_frame_note_inner = inside {$where_ ->
const_eval_frame_note_last = the failure occurred here const_eval_frame_note_last = the failure occurred here
const_eval_incompatible_arg_types =
calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}
const_eval_incompatible_calling_conventions = const_eval_incompatible_calling_conventions =
calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
const_eval_incompatible_return_types = const_eval_incompatible_return_types =
calling a function with return type {$callee_ty} passing return place of type {$caller_ty} calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
const_eval_incompatible_types =
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
const_eval_interior_mutable_borrow_escaping = const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this borrow of an interior mutable value refers to such a temporary .label = this borrow of an interior mutable value refers to such a temporary

View File

@@ -500,7 +500,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
InvalidNichedEnumVariantWritten { .. } => { InvalidNichedEnumVariantWritten { .. } => {
const_eval_invalid_niched_enum_variant_written const_eval_invalid_niched_enum_variant_written
} }
AbiMismatchArgument { .. } => const_eval_incompatible_types, AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
AbiMismatchReturn { .. } => const_eval_incompatible_return_types, AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
} }
} }
@@ -625,12 +625,16 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
diag.arg("data_size", info.data_size); diag.arg("data_size", info.data_size);
} }
InvalidNichedEnumVariantWritten { enum_ty } => { InvalidNichedEnumVariantWritten { enum_ty } => {
diag.arg("ty", enum_ty.to_string()); diag.arg("ty", enum_ty);
} }
AbiMismatchArgument { caller_ty, callee_ty } AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => {
| AbiMismatchReturn { caller_ty, callee_ty } => { diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output
diag.arg("caller_ty", caller_ty.to_string()); diag.arg("caller_ty", caller_ty);
diag.arg("callee_ty", callee_ty.to_string()); diag.arg("callee_ty", callee_ty);
}
AbiMismatchReturn { caller_ty, callee_ty } => {
diag.arg("caller_ty", caller_ty);
diag.arg("callee_ty", callee_ty);
} }
} }
} }

View File

@@ -270,6 +270,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
>, >,
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
callee_arg_idx: usize,
callee_arg: &mir::Place<'tcx>, callee_arg: &mir::Place<'tcx>,
callee_ty: Ty<'tcx>, callee_ty: Ty<'tcx>,
already_live: bool, already_live: bool,
@@ -298,6 +299,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Check compatibility // Check compatibility
if !self.check_argument_compat(caller_abi, callee_abi)? { if !self.check_argument_compat(caller_abi, callee_abi)? {
throw_ub!(AbiMismatchArgument { throw_ub!(AbiMismatchArgument {
arg_idx: callee_arg_idx,
caller_ty: caller_abi.layout.ty, caller_ty: caller_abi.layout.ty,
callee_ty: callee_abi.layout.ty callee_ty: callee_abi.layout.ty
}); });
@@ -424,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// this is a single iterator (that handles `spread_arg`), then // this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to // `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments. // not advance `caller_iter` for ignored arguments.
let mut callee_args_abis = callee_fn_abi.args.iter(); let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
for local in body.args_iter() { for local in body.args_iter() {
// Construct the destination place for this argument. At this point all // Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`. // locals are still dead, so we cannot construct a `PlaceTy`.
@@ -445,10 +447,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*self.tcx, *self.tcx,
); );
let callee_abi = callee_args_abis.next().unwrap(); let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument( self.pass_argument(
&mut caller_args, &mut caller_args,
callee_abi, callee_abi,
idx,
&dest, &dest,
field_ty, field_ty,
/* already_live */ true, /* already_live */ true,
@@ -456,10 +459,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} }
} else { } else {
// Normal argument. Cannot mark it as live yet, it might be unsized! // Normal argument. Cannot mark it as live yet, it might be unsized!
let callee_abi = callee_args_abis.next().unwrap(); let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument( self.pass_argument(
&mut caller_args, &mut caller_args,
callee_abi, callee_abi,
idx,
&dest, &dest,
ty, ty,
/* already_live */ false, /* already_live */ false,

View File

@@ -426,7 +426,12 @@ pub enum UndefinedBehaviorInfo<'tcx> {
/// Trying to set discriminant to the niched variant, but the value does not match. /// Trying to set discriminant to the niched variant, but the value does not match.
InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> }, InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
/// ABI-incompatible argument types. /// ABI-incompatible argument types.
AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, AbiMismatchArgument {
/// The index of the argument whose type is wrong.
arg_idx: usize,
caller_ty: Ty<'tcx>,
callee_ty: Ty<'tcx>,
},
/// ABI-incompatible return types. /// ABI-incompatible return types.
AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
} }

View File

@@ -382,7 +382,7 @@ pub fn report_error<'tcx>(
helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id)); helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id));
} }
} }
AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { AbiMismatchArgument { .. } => {
helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")); helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets"));
helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri")); helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri"));
} }

View File

@@ -1079,6 +1079,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
.position(|b| !b) .position(|b| !b)
{ {
throw_ub!(AbiMismatchArgument { throw_ub!(AbiMismatchArgument {
arg_idx: index,
caller_ty: caller_fn_abi.args[index].layout.ty, caller_ty: caller_fn_abi.args[index].layout.ty,
callee_ty: callee_fn_abi.args[index].layout.ty callee_ty: callee_fn_abi.args[index].layout.ty
}); });

View File

@@ -17,5 +17,5 @@ fn main() {
// These two types have the same size but are still not compatible. // These two types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) }; let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) };
g(Default::default()) //~ ERROR: calling a function with argument of type S passing data of type [i32; 4] g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4]
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4] error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4]
--> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC
| |
LL | g(Default::default()) LL | g(Default::default())

View File

@@ -3,5 +3,5 @@ fn main() {
let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) }; let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) };
g(42) //~ ERROR: calling a function with argument of type f32 passing data of type i32 g(42) //~ ERROR: type f32 passing argument of type i32
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32 error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC
| |
LL | g(42) LL | g(42)

View File

@@ -3,5 +3,5 @@ fn main() {
let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) }; let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) };
g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32 g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32
--> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC
| |
LL | g(&42 as *const i32) LL | g(&42 as *const i32)

View File

@@ -12,5 +12,5 @@ fn main() {
let fnptr: fn(S2) = callee; let fnptr: fn(S2) = callee;
let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) };
fnptr(S1(NonZero::new(1).unwrap())); fnptr(S1(NonZero::new(1).unwrap()));
//~^ ERROR: calling a function with argument of type S2 passing data of type S1 //~^ ERROR: type S2 passing argument of type S1
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1 error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1
--> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC
| |
LL | fnptr(S1(NonZero::new(1).unwrap())); LL | fnptr(S1(NonZero::new(1).unwrap()));

View File

@@ -5,5 +5,5 @@ fn main() {
let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) }; let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) };
g() //~ ERROR: calling a function with return type u32 passing return place of type () g() //~ ERROR: type u32 passing return place of type ()
} }

View File

@@ -6,8 +6,6 @@ LL | g()
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `main` at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC = note: inside `main` at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC

View File

@@ -3,5 +3,5 @@ fn main() {
let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) }; let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) };
g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32 g(42) //~ ERROR: type (i32, i32) passing argument of type i32
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC
| |
LL | g(42) LL | g(42)

View File

@@ -7,5 +7,5 @@ fn main() {
// These two vector types have the same size but are still not compatible. // These two vector types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) }; let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) };
g(Default::default()) //~ ERROR: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> g(Default::default()) //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
--> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC
| |
LL | g(Default::default()) LL | g(Default::default())

View File

@@ -16,6 +16,6 @@ fn main() {
} as u32; } as u32;
let _ = unsafe { let _ = unsafe {
close(fd); close(fd);
//~^ ERROR: calling a function with argument of type i32 passing data of type u32 //~^ ERROR: type i32 passing argument of type u32
}; };
} }

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32
--> tests/fail/shims/input_arg_mismatch.rs:LL:CC --> tests/fail/shims/input_arg_mismatch.rs:LL:CC
| |
LL | close(fd); LL | close(fd);

View File

@@ -6,8 +6,6 @@ LL | close(fd);
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: BACKTRACE: = note: BACKTRACE:
= note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC = note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC

View File

@@ -6,7 +6,7 @@ fn main() {
// the error should point to `become g(x)`, // the error should point to `become g(x)`,
// but tail calls mess up the backtrace it seems like... // but tail calls mess up the backtrace it seems like...
f(0); f(0);
//~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 //~^ error: type i32 passing argument of type u32
} }
fn f(x: u32) { fn f(x: u32) {

View File

@@ -1,4 +1,4 @@
error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32
--> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC
| |
LL | f(0); LL | f(0);