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:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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> },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
|||||||
@@ -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 ()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user