Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
7 changes: 6 additions & 1 deletion c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
24 changes: 24 additions & 0 deletions c2rust-transpile/tests/snapshots/exprs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsafe extern "C" fn(::core::ffi::c_int) -> ::core::ffi::c_int> = None;
let mut pftp_implicit: Option<unsafe extern "C" fn(int_t) -> ::core::ffi::c_int> = pfi;
let mut pftp_explicit: Option<unsafe extern "C" fn(int_t) -> ::core::ffi::c_int> = pfi;
let mut pftr_implicit: Option<unsafe extern "C" fn(::core::ffi::c_int) -> int_t> = pfi;
let mut pftr_explicit: Option<unsafe extern "C" fn(::core::ffi::c_int) -> int_t> = pfi;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsafe extern "C" fn(::core::ffi::c_int) -> ::core::ffi::c_int> = None;
let mut pftp_implicit: Option<unsafe extern "C" fn(int_t) -> ::core::ffi::c_int> = pfi;
let mut pftp_explicit: Option<unsafe extern "C" fn(int_t) -> ::core::ffi::c_int> = pfi;
let mut pftr_implicit: Option<unsafe extern "C" fn(::core::ffi::c_int) -> int_t> = pfi;
let mut pftr_explicit: Option<unsafe extern "C" fn(::core::ffi::c_int) -> int_t> = pfi;
}
Loading