diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 8616123..c895347 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2556,6 +2556,45 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { return false; } +// Returns the inner member and the replacement string. +static std::pair +replaceNonUniformLibcField(clang::MemberExpr *expr) { + // Example: ::struct stat::st_mtim::tv_sec -> ::libc::stat::st_mtime + struct Mapping { + const char *record; + const char *inner_field; + const char *leaf_field; + const char *replacement; + }; + static constexpr Mapping kFields[] = { + {"stat", "st_mtim", "tv_sec", "st_mtime"}, // Linux + {"stat", "st_mtimespec", "tv_sec", "st_mtime"}, // macOS + }; + + auto getNamedIdentifierOrNull = [](auto *decl) { + return decl && decl->getDeclName().isIdentifier() ? decl : nullptr; + }; + + if (auto leaf = getNamedIdentifierOrNull(expr->getMemberDecl())) { + if (auto inner = clang::dyn_cast( + expr->getBase()->IgnoreParenImpCasts())) { + if (auto field = getNamedIdentifierOrNull( + clang::dyn_cast(inner->getMemberDecl()))) { + if (getNamedIdentifierOrNull(field->getParent())) { + for (const auto &m : kFields) { + if (field->getParent()->getName() == m.record && + field->getName() == m.inner_field && + leaf->getName() == m.leaf_field) { + return {inner, m.replacement}; + } + } + } + } + } + } + return {nullptr, ""}; +} + void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { if (auto mapped = GetMappedAsString(expr); !mapped.empty()) { if (Mapper::ReturnsPointer(expr)) { @@ -2567,6 +2606,11 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } auto *member = expr->getMemberDecl(); + auto [inner, name_override] = replaceNonUniformLibcField(expr); + if (inner) { + expr = inner; + } + auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); @@ -2580,11 +2624,11 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { method && IsOverloadedMethod(method)) { StrCat(token::kDot); StrCat(GetOverloadedFunctionName(method)); - } else { - if (member->getDeclName().isIdentifier()) { - StrCat(token::kDot); - StrCat(GetNamedDeclAsString(member)); - } + } else if (!name_override.empty()) { + StrCat(token::kDot, name_override); + } else if (member->getDeclName().isIdentifier()) { + StrCat(token::kDot); + StrCat(GetNamedDeclAsString(member)); } } diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index 1f04dab..6094a5f 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -21,6 +21,7 @@ pub unsafe fn test_stat_0() { let mut st: stat = unsafe { std::mem::zeroed::() }; assert!(((((libc::stat(path as *const i8, (&mut st as *mut stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (5_i64)) as i32) != 0)); + assert!(((((st.st_mtime) > (0_i64)) as i32) != 0)); libc::unlink(path as *const i8); } pub unsafe fn test_fstat_1() { @@ -39,6 +40,7 @@ pub unsafe fn test_fstat_1() { let mut st: stat = unsafe { std::mem::zeroed::() }; assert!(((((libc::fstat(fd, (&mut st as *mut stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (11_i64)) as i32) != 0)); + assert!(((((st.st_mtime) > (0_i64)) as i32) != 0)); assert!(((((libc::fclose(fp)) == (0)) as i32) != 0)); libc::unlink(path as *const i8); } diff --git a/tests/unit/out/unsafe/union_tagged_struct_arms.rs b/tests/unit/out/unsafe/union_tagged_struct_arms.rs index a1f5955..6bf0689 100644 --- a/tests/unit/out/unsafe/union_tagged_struct_arms.rs +++ b/tests/unit/out/unsafe/union_tagged_struct_arms.rs @@ -73,7 +73,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - static mut items_0: [*mut u8; 3] = unsafe { + static mut items_4: [*mut u8; 3] = unsafe { [ b"a\0".as_ptr().cast_mut(), b"b\0".as_ptr().cast_mut(), @@ -83,7 +83,7 @@ unsafe fn main_0() -> i32 { let mut p_list: Branch = ::default(); p_list.choice = Choice::C_LIST; p_list.index = 0; - p_list.v.list.items = items_0.as_mut_ptr(); + p_list.v.list.items = items_4.as_mut_ptr(); p_list.v.list.count = 3_i64; p_list.v.list.cursor = 1_i64; assert!(((((p_list.v.list.count) == (3_i64)) as i32) != 0)); diff --git a/tests/unit/sys_stat.c b/tests/unit/sys_stat.c index a7e86ef..7c86e3d 100644 --- a/tests/unit/sys_stat.c +++ b/tests/unit/sys_stat.c @@ -14,6 +14,7 @@ static void test_stat(void) { struct stat st; assert(stat(path, &st) == 0); assert(st.st_size == 5); + assert(st.st_mtime > 0); unlink(path); } @@ -27,6 +28,7 @@ static void test_fstat(void) { struct stat st; assert(fstat(fd, &st) == 0); assert(st.st_size == 11); + assert(st.st_mtime > 0); assert(fclose(fp) == 0); unlink(path); }