From 582e2d309b10919c95a0d167d557f40539cfef93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Sep 2023 16:36:00 +0200 Subject: [PATCH 1/6] miri: catch function calls where the argument is caller-invalid / the return value callee-invalid --- ...1.rs => cast_fn_ptr_invalid_callee_arg.rs} | 0 ... => cast_fn_ptr_invalid_callee_arg.stderr} | 4 +-- .../cast_fn_ptr_invalid_callee_ret.rs | 28 +++++++++++++++ .../cast_fn_ptr_invalid_callee_ret.stderr | 15 ++++++++ .../cast_fn_ptr_invalid_caller_arg.rs | 34 +++++++++++++++++++ .../cast_fn_ptr_invalid_caller_arg.stderr | 20 +++++++++++ ...2.rs => cast_fn_ptr_invalid_caller_ret.rs} | 0 ... => cast_fn_ptr_invalid_caller_ret.stderr} | 4 +-- 8 files changed, 101 insertions(+), 4 deletions(-) rename tests/fail/validity/{cast_fn_ptr1.rs => cast_fn_ptr_invalid_callee_arg.rs} (100%) rename tests/fail/validity/{cast_fn_ptr1.stderr => cast_fn_ptr_invalid_callee_arg.stderr} (83%) create mode 100644 tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs create mode 100644 tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr create mode 100644 tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs create mode 100644 tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr rename tests/fail/validity/{cast_fn_ptr2.rs => cast_fn_ptr_invalid_caller_ret.rs} (100%) rename tests/fail/validity/{cast_fn_ptr2.stderr => cast_fn_ptr_invalid_caller_ret.stderr} (82%) diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs similarity index 100% rename from tests/fail/validity/cast_fn_ptr1.rs rename to tests/fail/validity/cast_fn_ptr_invalid_callee_arg.rs diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr similarity index 83% rename from tests/fail/validity/cast_fn_ptr1.stderr rename to tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr index 133e4b2c16..21e403b47f 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr_invalid_callee_arg.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr1.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC | LL | g(0usize as *const i32) | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | g(0usize as *const i32) = 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 = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs new file mode 100644 index 0000000000..7cdc15c609 --- /dev/null +++ b/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -0,0 +1,28 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that +// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// type. That way we never get an "invalid value constructed" error inside the function, it can +// only possibly be detected when the return value is passed to the caller. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn f() -> NonZeroU32 { + mir! { + { + let tmp = ptr::addr_of_mut!(RET); + let ptr = tmp as *mut u32; + *ptr = 0; + Return() + } + } +} + +fn main() { + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; + // There's a NonZeroU32-to-u32 transmute happening here + f(); //~ERROR: expected something greater or equal to 1 +} diff --git a/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr b/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr new file mode 100644 index 0000000000..ccfb889093 --- /dev/null +++ b/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + | +LL | f(); + | ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = 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 + = note: BACKTRACE: + = note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs new file mode 100644 index 0000000000..ee80186d4b --- /dev/null +++ b/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -0,0 +1,34 @@ +#![allow(internal_features)] +#![feature(core_intrinsics, custom_mir)] + +use std::intrinsics::mir::*; +use std::num::NonZeroU32; +use std::ptr; + +fn f(c: u32) { + println!("{c}"); +} + +// Call that function in a bad way, with an invalid NonZeroU32, but without +// ever materializing this as a NonZeroU32 value outside the call itself. +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn call(f: fn(NonZeroU32)) { + mir! { + let _res: (); + { + let c = 0; + let tmp = ptr::addr_of!(c); + let ptr = tmp as *const NonZeroU32; + // The call site now is a NonZeroU32-to-u32 transmute. + Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1 + } + retblock = { + Return() + } + } +} + +fn main() { + let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + call(f); +} diff --git a/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr b/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr new file mode 100644 index 0000000000..234c280400 --- /dev/null +++ b/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | Call(_res = f(*ptr), retblock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = 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 + = note: BACKTRACE: + = note: inside `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC +note: inside `main` + --> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC + | +LL | call(f); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs similarity index 100% rename from tests/fail/validity/cast_fn_ptr2.rs rename to tests/fail/validity/cast_fn_ptr_invalid_caller_ret.rs diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr similarity index 82% rename from tests/fail/validity/cast_fn_ptr2.stderr rename to tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr index 21001f2b46..bd9866acbd 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr_invalid_caller_ret.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: constructing invalid value: encountered a null reference - --> $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC | LL | let _x = g(); | ^^^ constructing invalid value: encountered a null reference @@ -7,7 +7,7 @@ LL | let _x = g(); = 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 = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + = note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 784f5450e375fd026f215077af42fe8254c84901 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Sep 2023 10:35:26 +0200 Subject: [PATCH 2/6] interpret: change ABI-compat test to be type-based, so the test is consistent across targets --- tests/pass/function_calls/abi_compat.rs | 39 +++++++++++++------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/pass/function_calls/abi_compat.rs b/tests/pass/function_calls/abi_compat.rs index 08be29115c..714d5c43b4 100644 --- a/tests/pass/function_calls/abi_compat.rs +++ b/tests/pass/function_calls/abi_compat.rs @@ -1,10 +1,11 @@ use std::mem; use std::num; +use std::ptr; #[derive(Copy, Clone, Default)] struct Zst; -fn test_abi_compat(t: T, u: U) { +fn test_abi_compat(t: T, u: U) { fn id(x: T) -> T { x } @@ -16,10 +17,10 @@ fn test_abi_compat(t: T, u: U) { // in both directions. let f: fn(T) -> T = id; let f: fn(U) -> U = unsafe { std::mem::transmute(f) }; - let _val = f(u); + let _val = f(u.clone()); let f: fn(U) -> U = id; let f: fn(T) -> T = unsafe { std::mem::transmute(f) }; - let _val = f(t); + let _val = f(t.clone()); // And then we do the same for `extern "C"`. let f: extern "C" fn(T) -> T = id_c; @@ -54,23 +55,25 @@ fn test_abi_newtype() { } fn main() { - // Here we check: - // - u32 vs char is allowed - // - u32 vs NonZeroU32/Option is allowed - // - reference vs raw pointer is allowed - // - references to things of the same size and alignment are allowed - // These are very basic tests that should work on all ABIs. However it is not clear that any of - // these would be stably guaranteed. Code that relies on this is equivalent to code that relies - // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields - // of a struct (even with `repr(C)`) will not always be accepted by Miri. - // Note that `bool` and `u8` are *not* compatible, at least on x86-64! - // One of them has `arg_ext: Zext`, the other does not. - // Similarly, `i32` and `u32` are not compatible on s390x due to different `arg_ext`. - test_abi_compat(0u32, 'x'); - test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); - test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); + // Here we check some of the guaranteed ABI compatibilities. + // Different integer types of the same size and sign. + if cfg!(target_pointer_width = "32") { + test_abi_compat(0usize, 0u32); + test_abi_compat(0isize, 0i32); + } else { + test_abi_compat(0usize, 0u64); + test_abi_compat(0isize, 0i64); + } + // Reference/pointer types with the same pointee. test_abi_compat(&0u32, &0u32 as *const u32); + test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32)); + test_abi_compat(&(), ptr::NonNull::<()>::dangling()); + // Reference/pointer types with different but sized pointees. test_abi_compat(&0u32, &([true; 4], [0u32; 0])); + // Guaranteed null-pointer-optimizations. + test_abi_compat(&0u32 as *const u32, Some(&0u32)); + test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); + test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // with the wrapped field. From 6ce8f43c31b195c7388eb1b1578ad5e3ca8ec062 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Sep 2023 10:50:14 +0200 Subject: [PATCH 3/6] give extra context to ABI mismatch errors --- src/diagnostics.rs | 24 ++++++++++++------- .../abi_mismatch_array_vs_struct.stderr | 2 ++ .../abi_mismatch_int_vs_float.stderr | 2 ++ .../abi_mismatch_raw_pointer.stderr | 2 ++ .../abi_mismatch_return_type.stderr | 2 ++ .../abi_mismatch_simple.stderr | 2 ++ .../abi_mismatch_vector.stderr | 2 ++ 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4f249acda1..cb095f94f3 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>( e: InterpErrorInfo<'tcx>, ) -> Option<(i64, bool)> { use InterpError::*; + use UndefinedBehaviorInfo::*; let mut msg = vec![]; @@ -271,7 +272,7 @@ pub fn report_error<'tcx, 'mir>( (title, helps) } else { let title = match e.kind() { - UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err)) + UndefinedBehavior(ValidationError(validation_err)) if matches!( validation_err.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer @@ -299,7 +300,7 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported(_) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], - UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) + UndefinedBehavior(AlignmentCheckFailed { .. }) if ecx.machine.check_alignment == AlignmentCheck::Symbolic => vec![ @@ -311,13 +312,20 @@ pub fn report_error<'tcx, 'mir>( (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ]; - if let UndefinedBehaviorInfo::PointerUseAfterFree(alloc_id, _) | UndefinedBehaviorInfo::PointerOutOfBounds { alloc_id, .. } = info { - if let Some(span) = ecx.machine.allocated_span(*alloc_id) { - helps.push((Some(span), format!("{:?} was allocated here:", alloc_id))); + match info { + PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => { + if let Some(span) = ecx.machine.allocated_span(*alloc_id) { + helps.push((Some(span), format!("{:?} was allocated here:", alloc_id))); + } + if let Some(span) = ecx.machine.deallocated_span(*alloc_id) { + helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id))); + } } - if let Some(span) = ecx.machine.deallocated_span(*alloc_id) { - helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id))); + AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { + helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets"))); + helps.push((None, format!("if you think this code should be accepted anyway, please report an issue"))); } + _ => {}, } helps } @@ -339,7 +347,7 @@ pub fn report_error<'tcx, 'mir>( // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early. let mut extra = String::new(); match e.kind() { - UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { + UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => { writeln!( extra, "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", diff --git a/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index 50d4228c11..d1ccaf8997 100644 --- a/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -6,6 +6,8 @@ LL | g(Default::default()) | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC diff --git a/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index a53126c733..3875c2617b 100644 --- a/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -6,6 +6,8 @@ LL | g(42) | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC diff --git a/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index 6eacfeece1..6d1bdfee00 100644 --- a/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -6,6 +6,8 @@ LL | g(&42 as *const i32) | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC diff --git a/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/tests/fail/function_pointers/abi_mismatch_return_type.stderr index eedc123577..07d76c90e5 100644 --- a/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -6,6 +6,8 @@ LL | g() | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC diff --git a/tests/fail/function_pointers/abi_mismatch_simple.stderr b/tests/fail/function_pointers/abi_mismatch_simple.stderr index bc500a90b7..7ac2bc2739 100644 --- a/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -6,6 +6,8 @@ LL | g(42) | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC diff --git a/tests/fail/function_pointers/abi_mismatch_vector.stderr b/tests/fail/function_pointers/abi_mismatch_vector.stderr index 7dcca1e85b..e082eb9e3e 100644 --- a/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -6,6 +6,8 @@ LL | g(Default::default()) | = 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: 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 = note: BACKTRACE: = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC From bc021e5ae73ddc7c2f40fea7ebda6baf53d30354 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Sep 2023 11:17:42 +0200 Subject: [PATCH 4/6] implement and test fn ptr ABI compatibility rules --- tests/pass/function_calls/abi_compat.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/pass/function_calls/abi_compat.rs b/tests/pass/function_calls/abi_compat.rs index 714d5c43b4..90dc73d19c 100644 --- a/tests/pass/function_calls/abi_compat.rs +++ b/tests/pass/function_calls/abi_compat.rs @@ -5,6 +5,8 @@ use std::ptr; #[derive(Copy, Clone, Default)] struct Zst; +fn id(x: T) -> T { x } + fn test_abi_compat(t: T, u: U) { fn id(x: T) -> T { x @@ -70,8 +72,11 @@ fn main() { test_abi_compat(&(), ptr::NonNull::<()>::dangling()); // Reference/pointer types with different but sized pointees. test_abi_compat(&0u32, &([true; 4], [0u32; 0])); + // `fn` types + test_abi_compat(main as fn(), id:: as fn(i32) -> i32); // Guaranteed null-pointer-optimizations. test_abi_compat(&0u32 as *const u32, Some(&0u32)); + test_abi_compat(main as fn(), Some(main as fn())); test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); From ccd36ff6b83e8d4d9139478695393ca8539cb90d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Sep 2023 11:36:35 +0200 Subject: [PATCH 5/6] implement and test ABI compatibility for transparent wrappers around NPO types --- tests/pass/function_calls/abi_compat.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/pass/function_calls/abi_compat.rs b/tests/pass/function_calls/abi_compat.rs index 90dc73d19c..2e1ab58db7 100644 --- a/tests/pass/function_calls/abi_compat.rs +++ b/tests/pass/function_calls/abi_compat.rs @@ -5,6 +5,10 @@ use std::ptr; #[derive(Copy, Clone, Default)] struct Zst; +#[repr(transparent)] +#[derive(Copy, Clone)] +struct Wrapper(T); + fn id(x: T) -> T { x } fn test_abi_compat(t: T, u: U) { @@ -35,9 +39,6 @@ fn test_abi_compat(t: T, u: U) { /// Ensure that `T` is compatible with various repr(transparent) wrappers around `T`. fn test_abi_newtype() { - #[repr(transparent)] - #[derive(Copy, Clone)] - struct Wrapper1(T); #[repr(transparent)] #[derive(Copy, Clone)] struct Wrapper2(T, ()); @@ -49,7 +50,7 @@ fn test_abi_newtype() { struct Wrapper3(Zst, T, [u8; 0]); let t = T::default(); - test_abi_compat(t, Wrapper1(t)); + test_abi_compat(t, Wrapper(t)); test_abi_compat(t, Wrapper2(t, ())); test_abi_compat(t, Wrapper2a((), t)); test_abi_compat(t, Wrapper3(Zst, t, [])); @@ -66,6 +67,7 @@ fn main() { test_abi_compat(0usize, 0u64); test_abi_compat(0isize, 0i64); } + test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); // Reference/pointer types with the same pointee. test_abi_compat(&0u32, &0u32 as *const u32); test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32)); @@ -77,8 +79,9 @@ fn main() { // Guaranteed null-pointer-optimizations. test_abi_compat(&0u32 as *const u32, Some(&0u32)); test_abi_compat(main as fn(), Some(main as fn())); - test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); + test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32))); + test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap()))); // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // with the wrapped field. From ac3c9a771a3618206b65d20c192e8267ea4d8074 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 10 Sep 2023 09:44:03 +0000 Subject: [PATCH 6/6] Remove EarlyErrorHandler argument from after_analysis callback It is only used by miri which can create a new one using the Session. --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 97718f1f4a..1e9219d4bb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_analysis<'tcx>( &mut self, - handler: &EarlyErrorHandler, _: &rustc_interface::interface::Compiler, queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { @@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.sess.fatal("miri cannot be run on programs that fail compilation"); } - init_late_loggers(handler, tcx); + let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format); + init_late_loggers(&handler, tcx); if !tcx.crate_types().contains(&CrateType::Executable) { tcx.sess.fatal("miri only makes sense on bin crates"); }