Skip to content
Merged
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
54 changes: 49 additions & 5 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,45 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
return false;
}

// Returns the inner member and the replacement string.
static std::pair<clang::MemberExpr *, std::string>
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<clang::MemberExpr>(
expr->getBase()->IgnoreParenImpCasts())) {
if (auto field = getNamedIdentifierOrNull(
clang::dyn_cast<clang::FieldDecl>(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)) {
Expand All @@ -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<clang::CXXThisExpr>(base->IgnoreCasts());
PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue);
Expand All @@ -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));
}
}

Expand Down
2 changes: 2 additions & 0 deletions tests/unit/out/unsafe/sys_stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub unsafe fn test_stat_0() {
let mut st: stat = unsafe { std::mem::zeroed::<stat>() };
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() {
Expand All @@ -39,6 +40,7 @@ pub unsafe fn test_fstat_1() {
let mut st: stat = unsafe { std::mem::zeroed::<stat>() };
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);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/out/unsafe/union_tagged_struct_arms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -83,7 +83,7 @@ unsafe fn main_0() -> i32 {
let mut p_list: Branch = <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));
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/sys_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}
Expand Down
Loading