diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index 9a6b8ea488..fb1e73a1e3 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -841,6 +841,160 @@ impl TypedAstContext { self.index(resolved_typ_id) } + /// Returns whether `qual_type_id1` and `qual_type_id2` describe the same type with the same + /// qualifiers. `resolver` is called on every `CTypeId` before recursing. + pub(crate) fn qual_types_eq( + &self, + qual_type_id1: CQualTypeId, + qual_type_id2: CQualTypeId, + resolver: &impl Fn(&Self, CTypeId) -> CTypeId, + ) -> bool { + qual_type_id1.qualifiers == qual_type_id2.qualifiers + && self.types_eq(qual_type_id1.ctype, qual_type_id2.ctype, resolver) + } + + /// Returns whether `type_id1` and `type_id2` describe the same type. + /// `resolver` is called on every `CTypeId` before recursing. + pub(crate) fn types_eq( + &self, + mut type_id1: CTypeId, + mut type_id2: CTypeId, + resolver: &impl Fn(&Self, CTypeId) -> CTypeId, + ) -> bool { + if type_id1 == type_id2 { + return true; + } + + type_id1 = resolver(self, type_id1); + type_id2 = resolver(self, type_id2); + type_id1 == type_id2 + || self.type_kinds_eq(&self[type_id1].kind, &self[type_id2].kind, resolver) + } + + /// Returns whether `kind1` and `kind2` describe the same type. + /// `resolver` is called on every `CTypeId` before recursing. + pub(crate) fn type_kinds_eq( + &self, + kind1: &CTypeKind, + kind2: &CTypeKind, + resolver: &impl Fn(&Self, CTypeId) -> CTypeId, + ) -> bool { + use CTypeKind::*; + + match (kind1, kind2) { + (Void, Void) + | (Bool, Bool) + | (SChar, SChar) + | (Short, Short) + | (Int, Int) + | (Long, Long) + | (LongLong, LongLong) + | (Int8, Int8) + | (Int16, Int16) + | (Int32, Int32) + | (Int64, Int64) + | (Int128, Int128) + | (IntPtr, IntPtr) + | (IntMax, IntMax) + | (SSize, SSize) + | (UChar, UChar) + | (UShort, UShort) + | (UInt, UInt) + | (ULong, ULong) + | (ULongLong, ULongLong) + | (UInt8, UInt8) + | (UInt16, UInt16) + | (UInt32, UInt32) + | (UInt64, UInt64) + | (UInt128, UInt128) + | (UIntPtr, UIntPtr) + | (UIntMax, UIntMax) + | (Size, Size) + | (Char, Char) + | (WChar, WChar) + | (PtrDiff, PtrDiff) + | (Half, Half) + | (BFloat16, BFloat16) + | (Float, Float) + | (Double, Double) + | (LongDouble, LongDouble) + | (Float128, Float128) + | (BuiltinFn, BuiltinFn) + | (UnhandledSveType, UnhandledSveType) => true, + + (Enum(decl_id1), Enum(decl_id2)) + | (Struct(decl_id1), Struct(decl_id2)) + | (Typedef(decl_id1), Typedef(decl_id2)) + | (Union(decl_id1), Union(decl_id2)) => decl_id1 == decl_id2, + + (Auto(type_id1), Auto(type_id2)) + | (Complex(type_id1), Complex(type_id2)) + | (Decayed(type_id1), Decayed(type_id2)) + | (Elaborated(type_id1), Elaborated(type_id2)) + | (Paren(type_id1), Paren(type_id2)) + | (TypeOf(type_id1), TypeOf(type_id2)) + | (IncompleteArray(type_id1), IncompleteArray(type_id2)) => { + self.types_eq(*type_id1, *type_id2, resolver) + } + + (Atomic(type_id1), Atomic(type_id2)) + | (BlockPointer(type_id1), BlockPointer(type_id2)) + | (Pointer(type_id1), Pointer(type_id2)) + | (Reference(type_id1), Reference(type_id2)) => { + self.qual_types_eq(*type_id1, *type_id2, resolver) + } + + (ConstantArray(type_id1, len1), ConstantArray(type_id2, len2)) => { + self.types_eq(*type_id1, *type_id2, resolver) && len1 == len2 + } + + (VariableArray(type_id1, expr_id1), VariableArray(type_id2, expr_id2)) => { + self.types_eq(*type_id1, *type_id2, resolver) && expr_id1 == expr_id2 + } + + (Vector(type_id1, len1), Vector(type_id2, len2)) => { + self.qual_types_eq(*type_id1, *type_id2, resolver) && len1 == len2 + } + + ( + Function( + result_type_id1, + ref argument_type_ids1, + is_variable_argument1, + is_noreturn1, + has_prototype1, + ), + Function( + result_type_id2, + ref argument_type_ids2, + is_variable_argument2, + is_noreturn2, + has_prototype2, + ), + ) => { + self.qual_types_eq(*result_type_id1, *result_type_id2, resolver) + && argument_type_ids1.len() == argument_type_ids2.len() + && argument_type_ids1 + .iter() + .zip(argument_type_ids2.iter()) + .all(|(&type_id1, &type_id2)| { + self.qual_types_eq(type_id1, type_id2, resolver) + }) + && is_variable_argument1 == is_variable_argument2 + && is_noreturn1 == is_noreturn2 + && has_prototype1 == has_prototype2 + } + + (Attributed(type_id1, ref attribute1), Attributed(type_id2, ref attribute2)) => { + self.qual_types_eq(*type_id1, *type_id2, resolver) && attribute1 == attribute2 + } + + (TypeOfExpr(expr_id1), TypeOfExpr(expr_id2)) => expr_id1 == expr_id2, + + _ => false, + } + } + /// Extract decl of referenced function. /// Looks for ImplicitCast(FunctionToPointerDecay, DeclRef(function_decl)) pub fn fn_declref_decl(&self, func_expr: CExprId) -> Option<&CDeclKind> { diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 9ba40228cd..6ef95ef64f 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -4261,7 +4261,12 @@ impl<'c> Translation<'c> { }) }); - if source_ty_kind == target_ty_kind && kind != CastKind::LValueToRValue { + if self.ast_context.type_kinds_eq( + source_ty_kind, + target_ty_kind, + &TypedAstContext::resolve_type_id, + ) && kind != CastKind::LValueToRValue + { return Ok(val); } diff --git a/c2rust-transpile/tests/snapshots/exprs.c b/c2rust-transpile/tests/snapshots/exprs.c index 09a3d8eab0..3fbcbc321d 100644 --- a/c2rust-transpile/tests/snapshots/exprs.c +++ b/c2rust-transpile/tests/snapshots/exprs.c @@ -114,3 +114,27 @@ void assign_result(void) { size_t s1 = l = 1; size_t s2 = l += 2; } + +void bypass_cast_with_typedef(void) { + // Primitive + int i = 0; + int_t t_implicit = i; + int_t t_explicit = (int_t) i; + + // Pointer + int *pi = 0; + int_t *pt_implicit = pi; + int_t *pt_explicit = (int_t *) pi; + + // Pointer to array + int (*pai)[2] = 0; + int_t (*pat_implicit)[2] = pai; + int_t (*pat_explicit)[2] = (int_t (*)[2]) pai; + + // Pointer to function + int (*pfi)(int) = 0; + int (*pftp_implicit)(int_t) = pfi; + int (*pftp_explicit)(int_t) = (int (*)(int_t)) pfi; + int_t (*pftr_implicit)(int) = pfi; + int_t (*pftr_explicit)(int) = (int_t (*)(int)) pfi; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap index 25c4af8ec1..20942ba008 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2021.clang15.snap @@ -152,3 +152,20 @@ pub unsafe extern "C" fn assign_result() { l = l.wrapping_add(2 as ::core::ffi::c_ulong); let mut s2: size_t = l as size_t; } +#[no_mangle] +pub unsafe extern "C" fn bypass_cast_with_typedef() { + let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; + let mut t_implicit: int_t = i; + let mut t_explicit: int_t = i; + let mut pi: *mut ::core::ffi::c_int = ::core::ptr::null_mut::<::core::ffi::c_int>(); + let mut pt_implicit: *mut int_t = pi; + let mut pt_explicit: *mut int_t = pi; + let mut pai: *mut [::core::ffi::c_int; 2] = ::core::ptr::null_mut::<[::core::ffi::c_int; 2]>(); + let mut pat_implicit: *mut [int_t; 2] = pai; + let mut pat_explicit: *mut [int_t; 2] = pai; + let mut pfi: Option ::core::ffi::c_int> = None; + let mut pftp_implicit: Option ::core::ffi::c_int> = pfi; + let mut pftp_explicit: Option ::core::ffi::c_int> = pfi; + let mut pftr_implicit: Option int_t> = pfi; + let mut pftr_explicit: Option int_t> = pfi; +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap index a7abaf5f3b..60ee7b1c96 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@exprs.c.2024.clang15.snap @@ -152,3 +152,20 @@ pub unsafe extern "C" fn assign_result() { l = l.wrapping_add(2 as ::core::ffi::c_ulong); let mut s2: size_t = l as size_t; } +#[unsafe(no_mangle)] +pub unsafe extern "C" fn bypass_cast_with_typedef() { + let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; + let mut t_implicit: int_t = i; + let mut t_explicit: int_t = i; + let mut pi: *mut ::core::ffi::c_int = ::core::ptr::null_mut::<::core::ffi::c_int>(); + let mut pt_implicit: *mut int_t = pi; + let mut pt_explicit: *mut int_t = pi; + let mut pai: *mut [::core::ffi::c_int; 2] = ::core::ptr::null_mut::<[::core::ffi::c_int; 2]>(); + let mut pat_implicit: *mut [int_t; 2] = pai; + let mut pat_explicit: *mut [int_t; 2] = pai; + let mut pfi: Option ::core::ffi::c_int> = None; + let mut pftp_implicit: Option ::core::ffi::c_int> = pfi; + let mut pftp_explicit: Option ::core::ffi::c_int> = pfi; + let mut pftr_implicit: Option int_t> = pfi; + let mut pftr_explicit: Option int_t> = pfi; +}