diff --git a/c2rust-analyze/src/dataflow/type_check.rs b/c2rust-analyze/src/dataflow/type_check.rs index 5472bb9b96..2626890269 100644 --- a/c2rust-analyze/src/dataflow/type_check.rs +++ b/c2rust-analyze/src/dataflow/type_check.rs @@ -13,6 +13,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{SubstsRef, Ty, TyKind}; +use std::iter; /// Visitor that walks over the MIR, computing types of rvalues/operands/places and generating /// constraints as a side effect. @@ -135,12 +136,35 @@ impl<'tcx> TypeChecker<'tcx, '_> { PointerCast::ArrayToPointer => {} PointerCast::Unsize => {} } - self.do_assign_pointer_ids(to_lty.label, from_lty.label) - // TODO add other dataflow constraints + + // We would normally do `self.do_assign`, + // but we can't do a normal `self.do_equivalence_nested` (inside `self.do_assign`), + // so we do the `self.do_assign_pointer_ids` from `self.do_assign`, + // and then do the body of `self.do_equivalence_nested`, + // but after the extra outer layers are stripped. + + self.do_assign_pointer_ids(to_lty.label, from_lty.label); + + // Each of these ptr casts needs at least the outer layer stripped (e.x. `&`, `*mut`, `fn`), + // but then after that, these ptr casts below + // needs more layers stripped to reach the types that are equivalent. + let strip_from = |lty: LTy<'tcx>| match ptr_cast { + PointerCast::ArrayToPointer => lty.args[0], + PointerCast::Unsize => lty.args[0], + _ => lty, + }; + let strip_to = |lty: LTy<'tcx>| match ptr_cast { + PointerCast::Unsize => lty.args[0], + _ => lty, + }; + for (&from_lty, &to_lty) in iter::zip(from_lty.args, to_lty.args) { + self.do_unify(strip_from(from_lty), strip_to(to_lty)); + } } CastKind::Misc => { match is_transmutable_ptr_cast(from_ty, to_ty) { Some(true) => { + self.do_assign_pointer_ids(to_lty.label, from_lty.label); // TODO add other dataflow constraints }, Some(false) => ::log::error!("TODO: unsupported ptr-to-ptr cast between pointee types not yet supported as safely transmutable: `{from_ty:?} as {to_ty:?}`"), diff --git a/c2rust-analyze/tests/analyze/string_casts.rs b/c2rust-analyze/tests/analyze/string_casts.rs index ea0c837a59..9aa7c9bde8 100644 --- a/c2rust-analyze/tests/analyze/string_casts.rs +++ b/c2rust-analyze/tests/analyze/string_casts.rs @@ -33,3 +33,58 @@ pub fn cast_from_literal() { pub fn cast_from_literal_explicit() { std::ptr::addr_of!(*b"\0") as *const u8 as *const core::ffi::c_char; } + +/// [`PointerCast::ReifyFnPointer`] +pub fn cast_fn_item_to_fn_ptr() { + fn f(x: u8) -> i8 { + x as i8 + } + f as fn(u8) -> i8; +} + +/// [`PointerCast::UnsafeFnPointer`] +/// +/// ```shell +/// thread 'rustc' panicked at 'not yet implemented', c2rust-analyze/src/labeled_ty.rs:372:17 +/// ``` +#[cfg(any())] +pub fn cast_fn_ptr_to_unsafe_fn_ptr(f: fn(u8) -> i8) { + f as unsafe fn(u8) -> i8; +} + +/// [`PointerCast::ClosureFnPointer`] +/// Unhandled very early on. +#[cfg(any())] +pub fn cast_closure_to_fn_ptr() { + (|b: u8| b as i8) as fn(u8) -> i8; +} + +/// [`PointerCast::MutToConstPointer`] +/// +/// ```shell +/// thread 'rustc' panicked at 'not yet implemented', c2rust-analyze/src/labeled_ty.rs:372:17 +/// ``` +#[cfg(any())] +pub fn cast_mut_to_const_ptr(p: *mut i32) { + p as *const i32; +} + +/// Meant to be [`PointerCast::ArrayToPointer`], but is [`CastKind::Misc`]. +pub fn cast_array_ptr_to_ptr(p: *const [i32; 1]) { + p as *const i32; +} + +/// [`PointerCast::Unsize`] +/// +/// ```shell +/// thread 'rustc' panicked at 'expected to find only one Assign statement, but got multiple', c2rust-analyze/src/rewrite/expr/hir_op.rs:126:21 +/// ``` +#[cfg(any())] +pub fn cast_unsize_direct(a: &[i32; 1]) { + a as &[i32]; +} + +/// [`PointerCast::Unsize`] +pub fn cast_unsize_indirect(a: &[i32; 1]) { + let _ = a.as_ptr(); +}