From 50db0b3eb8f3230ee1b9d91b043f9b5bf2267c1a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:46:25 +0100 Subject: [PATCH 01/10] Add rules for libc fields wrapped in macros --- rules/ip/src.c | 2 ++ rules/ip/tgt_refcount.rs | 4 ++++ rules/ip/tgt_unsafe.rs | 4 ++++ rules/stat/src.c | 2 ++ rules/stat/tgt_refcount.rs | 4 ++++ rules/stat/tgt_unsafe.rs | 4 ++++ 6 files changed, 20 insertions(+) diff --git a/rules/ip/src.c b/rules/ip/src.c index 8a4dd2639..f8073ca11 100644 --- a/rules/ip/src.c +++ b/rules/ip/src.c @@ -19,3 +19,5 @@ int f5(void) { return IPPROTO_MPTCP; } #endif int f6(void) { return TCP_NODELAY; } + +uint8_t *f7(struct in6_addr a0) { return a0.s6_addr; } diff --git a/rules/ip/tgt_refcount.rs b/rules/ip/tgt_refcount.rs index 93d61e137..c91d6490c 100644 --- a/rules/ip/tgt_refcount.rs +++ b/rules/ip/tgt_refcount.rs @@ -18,3 +18,7 @@ fn t3() -> libcc2rs::SockaddrIn6 { fn t4() -> libcc2rs::In6Addr { Default::default() } + +fn f7(a0: Ptr) -> Ptr { + In6Addr::s6_addr(a0) +} diff --git a/rules/ip/tgt_unsafe.rs b/rules/ip/tgt_unsafe.rs index caba50fa9..7395fe0e1 100644 --- a/rules/ip/tgt_unsafe.rs +++ b/rules/ip/tgt_unsafe.rs @@ -38,3 +38,7 @@ unsafe fn f5() -> i32 { unsafe fn f6() -> i32 { libc::TCP_NODELAY } + +unsafe fn f7(a0: *mut ::libc::in6_addr) -> *mut [u8; 16] { + &raw mut (*a0).s6_addr +} diff --git a/rules/stat/src.c b/rules/stat/src.c index 9e399f741..03060ca9f 100644 --- a/rules/stat/src.c +++ b/rules/stat/src.c @@ -14,3 +14,5 @@ int f1(const char *pathname, struct stat *statbuf) { int f2(int fd, struct stat *statbuf) { return fstat(fd, statbuf); } int f3(const char *pathname, mode_t mode) { return mkdir(pathname, mode); } + +time_t f4(struct stat a0) { return a0.st_mtime; } diff --git a/rules/stat/tgt_refcount.rs b/rules/stat/tgt_refcount.rs index 045040b1b..cfca8ead1 100644 --- a/rules/stat/tgt_refcount.rs +++ b/rules/stat/tgt_refcount.rs @@ -45,3 +45,7 @@ fn f3(a0: Ptr, a1: ::libc::mode_t) -> i32 { } } } + +fn f4(a0: Ptr) -> Ptr { + field_ptr!(a0, st_mtime) +} diff --git a/rules/stat/tgt_unsafe.rs b/rules/stat/tgt_unsafe.rs index c6da0a5a6..694b7b8ed 100644 --- a/rules/stat/tgt_unsafe.rs +++ b/rules/stat/tgt_unsafe.rs @@ -16,3 +16,7 @@ unsafe fn f2(a0: i32, a1: *mut ::libc::stat) -> i32 { unsafe fn f3(a0: *const libc::c_char, a1: ::libc::mode_t) -> i32 { libc::mkdir(a0, a1 as ::libc::mode_t) } + +unsafe fn f4(a0: *mut ::libc::stat) -> *mut ::libc::time_t { + &raw mut (*a0).st_mtime +} From bb6e547c3865602e020305ec27ab779b97678906 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:46:43 +0100 Subject: [PATCH 02/10] Drop ReplaceNonUniformLibcField --- cpp2rust/converter/converter.cpp | 8 +--- cpp2rust/converter/converter_lib.cpp | 45 +++---------------- cpp2rust/converter/converter_lib.h | 3 -- .../converter/models/converter_refcount.cpp | 25 +++++++---- cpp2rust/converter/rules/decls.cpp | 21 +++++++++ cpp2rust/converter/rules/decls.h | 4 ++ cpp2rust/converter/rules/expr_matcher.cpp | 12 ++++- cpp2rust/converter/rules/rule_keys.cpp | 6 +++ cpp2rust/converter/rules/rules_loader.cpp | 6 +++ 9 files changed, 71 insertions(+), 59 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5aba7cecc..3d87a0264 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3521,6 +3521,7 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { if (auto mapped = GetMappedAsString(expr); !mapped.empty()) { if (RuleRegistry::ReturnsPointer(ctx_, expr)) { + PushParen paren(*this, expr->getType()->isArrayType()); StrCat(token::kStar, mapped); } else { StrCat(mapped); @@ -3529,11 +3530,6 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } auto *member = expr->getMemberDecl(); - auto [inner, record, name_override] = ReplaceNonUniformLibcField(expr); - if (inner) { - expr = inner; - } - auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()) && !ThisIsRustPtr() && !AsLambdaOperatorCall(curr_function_); @@ -3552,8 +3548,6 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { method && IsOverloadedMethod(method)) { StrCat(token::kDot); StrCat(GetMethodName(method)); - } else if (!name_override.empty()) { - StrCat(token::kDot, name_override); } else if (member->getDeclName().isIdentifier()) { StrCat(token::kDot); StrCat(GetNamedDeclAsString(member)); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index edfdaa46f..ec6ba73f8 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -29,6 +29,7 @@ #include "converter/lex.h" #include "converter/mapper.h" #include "converter/printer.h" +#include "converter/rules/decls.h" #include "converter/rules/registry.h" // https://doc.rust-lang.org/reference/keywords.html @@ -223,45 +224,6 @@ clang::Expr *SubscriptedArray(clang::Expr *base) { } // TODO: this will be gone when the AST matcher lands -std::tuple -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 - {"in6_addr", "__in6_u", "__u6_addr8", "s6_addr"}, - }; - - 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, field->getParent(), m.replacement}; - } - } - } - } - } - } - return {nullptr, nullptr, ""}; -} - bool IsStringLiteralExpr(const clang::Expr *expr) { const auto *stripped = expr->IgnoreParens()->IgnoreImplicit(); return clang::isa(stripped) || @@ -1841,7 +1803,10 @@ BuildUnifiedArgs(clang::Expr *expr, clang::Expr **args, unsigned num_args) { if (auto *mcall = clang::dyn_cast(expr)) { all_args.push_back(mcall->getImplicitObjectArgument()); } else if (auto *member = clang::dyn_cast(expr)) { - all_args.push_back(member->getBase()); + auto *base = RuleDecls::GetMacroMemberBase( + member->getMemberDecl()->getASTContext().getSourceManager(), member); + all_args.push_back(const_cast(base ? base + : member->getBase())); } for (unsigned i = 0; i < num_args; ++i) { all_args.push_back(args[i]); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index f46c81958..04e4aebcc 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -60,9 +60,6 @@ bool IsUnionArrayMember(const clang::Expr *base); clang::Expr *SubscriptedArray(clang::Expr *base); -std::tuple -ReplaceNonUniformLibcField(clang::MemberExpr *expr); - bool IsStringLiteralExpr(const clang::Expr *expr); bool IsCodeUnitStringLiteral(const clang::StringLiteral *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index c6f98afaf..2dd81d5e6 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1974,14 +1974,7 @@ void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) { auto member = expr->getMemberDecl(); auto *record = clang::cast(member->getDeclContext()); auto name = GetNamedDeclAsString(member); - auto *accessed = expr; - if (auto [inner, libc_record, libc_name] = ReplaceNonUniformLibcField(expr); - inner) { - record = libc_record; - name = libc_name; - accessed = inner; - } - auto ptr = ConvertRecordPtr(accessed); + auto ptr = ConvertRecordPtr(expr); auto str = std::format("{}::{}({}{})", GetRecordName(record), name, ptr, isFresh() ? "" : ".clone()"); @@ -2021,6 +2014,22 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) { } bool known = Mapper::Contains(ctx_, expr); + if (known && RuleRegistry::ReturnsPointer(ctx_, expr)) { + auto str = GetMappedAsString(expr); + if (isAddrOf()) { + StrCat(str); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + } + if (isLValue()) { + pending_deref_.set(str, /*fresh=*/true); + return false; + } + StrCat(DerefPtrExpr(str, expr->getType())); + SetDerefFreshness(expr->getType()); + return false; + } + if (auto *method = clang::dyn_cast(member); method && !known) { if (IsMethodOnPtr(method)) { diff --git a/cpp2rust/converter/rules/decls.cpp b/cpp2rust/converter/rules/decls.cpp index cb37c38f8..adb551e09 100644 --- a/cpp2rust/converter/rules/decls.cpp +++ b/cpp2rust/converter/rules/decls.cpp @@ -50,6 +50,27 @@ const clang::Expr *GetReturned(const clang::FunctionDecl *rule) { return returned; } +const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, + const clang::MemberExpr *member) { + auto loc = member->getMemberLoc(); + if (!loc.isMacroID()) { + return nullptr; + } + auto file = sm.getFileID(loc); + const auto &expansion = sm.getSLocEntry(file).getExpansion(); + if (expansion.isMacroArgExpansion() || expansion.isFunctionMacroExpansion()) { + return nullptr; + } + const clang::Expr *base = member->getBase(); + while (true) { + auto inner = llvm::dyn_cast(base->IgnoreParenImpCasts()); + if (!inner || sm.getFileID(inner->getMemberLoc()) != file) { + return base; + } + base = inner->getBase(); + } +} + clang::QualType EnableIfSameType(const clang::Decl *rule) { auto tmpl = llvm::dyn_cast(rule); if (!tmpl) { diff --git a/cpp2rust/converter/rules/decls.h b/cpp2rust/converter/rules/decls.h index 7169a72e2..6c97da7c8 100644 --- a/cpp2rust/converter/rules/decls.h +++ b/cpp2rust/converter/rules/decls.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,9 @@ const clang::Expr *SkipImplicit(const clang::Expr *expr); const clang::Expr *GetReturned(const clang::FunctionDecl *rule); +const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, + const clang::MemberExpr *member); + clang::QualType EnableIfSameType(const clang::Decl *rule); std::optional> diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index 01e37e6dc..5286a8a7f 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -92,6 +92,12 @@ ResolvedDecl getResolvedDecl(clang::ASTContext &ctx, const clang::Expr *expr, } else if (auto construct = llvm::dyn_cast(expr)) { return construct->getConstructor()->getCanonicalDecl(); } else if (auto member = llvm::dyn_cast(expr)) { + auto &sm = ctx.getSourceManager(); + if (RuleDecls::GetMacroMemberBase(sm, member)) { + return MacroUsage{clang::Lexer::getImmediateMacroName( + member->getMemberLoc(), sm, ctx.getLangOpts()) + .str()}; + } return member->getMemberDecl()->getCanonicalDecl(); } else if (auto ref = llvm::dyn_cast(expr)) { return ref->getDecl()->getCanonicalDecl(); @@ -144,7 +150,11 @@ std::vector getOperands(clang::ASTContext &ctx, } else if (auto construct = llvm::dyn_cast(expr)) { operands.assign(construct->arg_begin(), construct->arg_end()); } else if (auto member = llvm::dyn_cast(expr)) { - auto base = member->getBase()->IgnoreParenImpCasts(); + auto macro_base = + RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member); + auto base = const_cast(macro_base ? macro_base + : member->getBase()) + ->IgnoreParenImpCasts(); if (auto arrow = llvm::dyn_cast(base); arrow && arrow->getOperator() == clang::OO_Arrow) { base = arrow->getArg(0); diff --git a/cpp2rust/converter/rules/rule_keys.cpp b/cpp2rust/converter/rules/rule_keys.cpp index 0468187d6..3ad820322 100644 --- a/cpp2rust/converter/rules/rule_keys.cpp +++ b/cpp2rust/converter/rules/rule_keys.cpp @@ -160,6 +160,12 @@ std::optional getExprKey(clang::ASTContext &ctx, return Unqualified{ref->getDeclName()}; } if (auto member = llvm::dyn_cast(expr)) { + auto &sm = ctx.getSourceManager(); + if (RuleDecls::GetMacroMemberBase(sm, member)) { + auto macro = clang::Lexer::getImmediateMacroName(member->getMemberLoc(), + sm, ctx.getLangOpts()); + return Unqualified{clang::DeclarationName(&ctx.Idents.get(macro))}; + } return getDeclKey(member->getMemberDecl()); } if (auto ref = llvm::dyn_cast(expr)) { diff --git a/cpp2rust/converter/rules/rules_loader.cpp b/cpp2rust/converter/rules/rules_loader.cpp index 1373ce9da..7b0e4d319 100644 --- a/cpp2rust/converter/rules/rules_loader.cpp +++ b/cpp2rust/converter/rules/rules_loader.cpp @@ -442,6 +442,12 @@ std::string ExprKey(clang::ASTContext &ctx, const clang::Expr *expr) { return FunctionKey(construct->getConstructor()); } if (auto member = llvm::dyn_cast(expr)) { + if (RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member)) { + return clang::Lexer::getImmediateMacroName(member->getMemberLoc(), + ctx.getSourceManager(), + ctx.getLangOpts()) + .str(); + } return DeclKey(member->getMemberDecl()); } if (auto ref = llvm::dyn_cast(expr)) { From 785d7d1473085a20d193810a8a1c50017ea448ce Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:46:53 +0100 Subject: [PATCH 03/10] Update tests --- cpp2rust/converter/rules/rules_loader.cpp | 1 + tests/unit/inet_pton_ntop.c | 24 ++++++++++++++++++++++ tests/unit/sys_stat.c | 25 +++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/cpp2rust/converter/rules/rules_loader.cpp b/cpp2rust/converter/rules/rules_loader.cpp index 7b0e4d319..73f5c1bfe 100644 --- a/cpp2rust/converter/rules/rules_loader.cpp +++ b/cpp2rust/converter/rules/rules_loader.cpp @@ -25,6 +25,7 @@ #include #include "converter/converter_lib.h" +#include "converter/rules/decls.h" #include "logging.h" namespace cpp2rust::RulesLoader { diff --git a/tests/unit/inet_pton_ntop.c b/tests/unit/inet_pton_ntop.c index 757c65ae7..55ded2d0b 100644 --- a/tests/unit/inet_pton_ntop.c +++ b/tests/unit/inet_pton_ntop.c @@ -2,7 +2,31 @@ #include #include +static void test_s6_addr_access(void) { + const unsigned char loopback[16] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1}; + struct in6_addr addr; + struct in6_addr *ap = &addr; + memcpy(addr.s6_addr, loopback, 16); + assert(memcmp(ap->s6_addr, loopback, 16) == 0); + addr.s6_addr[0] = 0x20; + ap->s6_addr[1] = 0x01; + assert(addr.s6_addr[0] == 0x20 && ap->s6_addr[1] == 0x01); + addr.s6_addr[15] += 4; + ap->s6_addr[15]++; + assert(addr.s6_addr[15] == 6); + unsigned char *bytes = addr.s6_addr; + bytes[2] = 7; + assert(ap->s6_addr[2] == 7); + unsigned char *fourth = &ap->s6_addr[3]; + *fourth = 8; + assert(addr.s6_addr[3] == 8); + memcpy(ap->s6_addr, loopback, 16); + assert(memcmp(addr.s6_addr, loopback, 16) == 0); +} + int main(void) { + test_s6_addr_access(); unsigned char buf[16]; assert(inet_pton(AF_INET, "1.2.3.4", buf) == 1); assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 3 && buf[3] == 4); diff --git a/tests/unit/sys_stat.c b/tests/unit/sys_stat.c index 433665ee0..e4d140fbc 100644 --- a/tests/unit/sys_stat.c +++ b/tests/unit/sys_stat.c @@ -32,8 +32,33 @@ static void test_fstat(void) { unlink(path); } +static void test_st_mtime_access(void) { + struct stat st; + struct stat *sp = &st; + st.st_mtime = 5; + assert(st.st_mtime == 5); + sp->st_mtime = 6; + assert(sp->st_mtime == 6); + st.st_mtime += 2; + assert(st.st_mtime == 8); + sp->st_mtime -= 1; + assert(sp->st_mtime == 7); + st.st_mtime++; + ++sp->st_mtime; + assert(st.st_mtime == 9); + time_t *mtime = &st.st_mtime; + *mtime = 10; + assert(st.st_mtime == 10); + time_t *mtime_via_ptr = &sp->st_mtime; + *mtime_via_ptr = 11; + assert(*mtime == 11); + time_t copy = sp->st_mtime; + assert(copy == 11); +} + int main(void) { test_stat(); test_fstat(); + test_st_mtime_access(); return 0; } From e7bbd3475bd9a1b64f2d360fea639d0a421c2f6d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:48:47 +0100 Subject: [PATCH 04/10] Update tests --- tests/unit/out/refcount/inet_pton_ntop.rs | 106 ++++++++++++++++++++++ tests/unit/out/refcount/sys_stat.rs | 32 ++++++- tests/unit/out/unsafe/inet_pton_ntop.rs | 89 ++++++++++++++++++ tests/unit/out/unsafe/sys_stat.rs | 28 +++++- 4 files changed, 251 insertions(+), 4 deletions(-) diff --git a/tests/unit/out/refcount/inet_pton_ntop.rs b/tests/unit/out/refcount/inet_pton_ntop.rs index 5bc235324..ebdcd63cb 100644 --- a/tests/unit/out/refcount/inet_pton_ntop.rs +++ b/tests/unit/out/refcount/inet_pton_ntop.rs @@ -6,11 +6,117 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +pub fn test_s6_addr_access_0() { + let loopback: Value> = Rc::new(RefCell::new(Box::new([ + 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, + 1_u8, + ]))); + let addr: Value = Rc::new(RefCell::new(Default::default())); + let mut ap: Ptr = (addr.as_pointer()); + { + ((In6Addr::s6_addr(addr.as_pointer()) as Ptr) as Ptr) + .to_any() + .memcpy( + &((loopback.as_pointer() as Ptr) as Ptr).to_any(), + 16_usize as usize, + ); + ((In6Addr::s6_addr(addr.as_pointer()) as Ptr) as Ptr).to_any() + }; + assert!( + (((((anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::) + as Ptr) + .to_any() + .memcmp( + &((loopback.as_pointer() as Ptr::) as Ptr).to_any(), + 16_usize + ) + == 0) as i32) + != 0) + ); + elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 0).write(32_u8); + elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 1).write(1_u8); + assert!( + ((((((((elem!( + (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() + as Ptr::), + 0 + ) + .read()) as i32) + == 32) as i32) + != 0) + && (((((elem!( + (anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::), + 1 + ) + .read()) as i32) + == 1) as i32) + != 0)) as i32) + != 0) + ); + elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 15).write({ + (((elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 15).read()) as i32) + 4) as u8 + }); + elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 15).with_mut(|__v| __v.postfix_inc()); + assert!( + (((((elem!( + (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() + as Ptr::), + 15 + ) + .read()) as i32) + == 6) as i32) + != 0) + ); + let mut bytes: Ptr = (In6Addr::s6_addr(addr.as_pointer()) as Ptr); + elem!(bytes, 2).write(7_u8); + assert!( + (((((elem!( + (anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::), + 2 + ) + .read()) as i32) + == 7) as i32) + != 0) + ); + let mut fourth: Ptr = ((In6Addr::s6_addr((ap).clone()) as Ptr).offset((3) as isize)); + fourth.write(8_u8); + assert!( + (((((elem!( + (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() + as Ptr::), + 3 + ) + .read()) as i32) + == 8) as i32) + != 0) + ); + { + ((In6Addr::s6_addr((ap).clone()) as Ptr) as Ptr) + .to_any() + .memcpy( + &((loopback.as_pointer() as Ptr) as Ptr).to_any(), + 16_usize as usize, + ); + ((In6Addr::s6_addr((ap).clone()) as Ptr) as Ptr).to_any() + }; + assert!( + (((((anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() + as Ptr::) as Ptr) + .to_any() + .memcmp( + &((loopback.as_pointer() as Ptr::) as Ptr).to_any(), + 16_usize + ) + == 0) as i32) + != 0) + ); +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { + ({ test_s6_addr_access_0() }); let buf: Value> = Rc::new(RefCell::new((0..16).map(|_| 0_u8).collect::>())); assert!( (((if libc::AF_INET == libc::AF_INET { diff --git a/tests/unit/out/refcount/sys_stat.rs b/tests/unit/out/refcount/sys_stat.rs index 2c058777a..8613c53ae 100644 --- a/tests/unit/out/refcount/sys_stat.rs +++ b/tests/unit/out/refcount/sys_stat.rs @@ -45,7 +45,7 @@ pub fn test_stat_0() { != 0) ); assert!(((({ (*st.borrow()).st_size } == 5_i64) as i32) != 0)); - assert!(((({ (*st.borrow()).st_mtime } > 0_i64) as i32) != 0)); + assert!(((({ (*st.borrow()).st_mtim.tv_sec } > 0_i64) as i32) != 0)); match nix::unistd::unlink(path.to_rust_string().as_str()) { Ok(()) => 0, Err(__e) => { @@ -87,7 +87,7 @@ pub fn test_fstat_1() { != 0) ); assert!(((({ (*st.borrow()).st_size } == 11_i64) as i32) != 0)); - assert!(((({ (*st.borrow()).st_mtime } > 0_i64) as i32) != 0)); + assert!(((({ (*st.borrow()).st_mtim.tv_sec } > 0_i64) as i32) != 0)); assert!( ((({ let __r = fp.with(|__f| __f.close()); @@ -104,6 +104,33 @@ pub fn test_fstat_1() { } }; } +pub fn test_st_mtime_access_2() { + let st: Value = Rc::new(RefCell::new(Default::default())); + let mut sp: Ptr = (st.as_pointer()); + field_ptr!(st.as_pointer(), st_mtime).write(5_i64); + assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 5_i64) as i32) != 0)); + field_ptr!(sp, st_mtime).write(6_i64); + assert!((((sp.with(|__s| __s.st_mtim.tv_sec) == 6_i64) as i32) != 0)); + { + field_ptr!(st.as_pointer(), st_mtime).with_mut(|__v| *__v = *__v + 2_i64) + }; + assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 8_i64) as i32) != 0)); + { + field_ptr!(sp, st_mtime).with_mut(|__v| *__v = *__v - 1_i64) + }; + assert!((((sp.with(|__s| __s.st_mtim.tv_sec) == 7_i64) as i32) != 0)); + field_ptr!(st.as_pointer(), st_mtime).with_mut(|__v| __v.postfix_inc()); + field_ptr!(sp, st_mtime).with_mut(|__v| __v.prefix_inc()); + assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 9_i64) as i32) != 0)); + let mut mtime: Ptr = (field_ptr!(st.as_pointer(), st_mtime)); + mtime.write(10_i64); + assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 10_i64) as i32) != 0)); + let mut mtime_via_ptr: Ptr = (field_ptr!(sp, st_mtime)); + mtime_via_ptr.write(11_i64); + assert!(((((mtime.read()) == 11_i64) as i32) != 0)); + let mut copy: i64 = (field_ptr!(sp, st_mtime).read()); + assert!((((copy == 11_i64) as i32) != 0)); +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -111,6 +138,7 @@ pub fn main() { fn main_0() -> i32 { ({ test_stat_0() }); ({ test_fstat_1() }); + ({ test_st_mtime_access_2() }); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/inet_pton_ntop.rs b/tests/unit/out/unsafe/inet_pton_ntop.rs index 4bfb80f17..d830f79ff 100644 --- a/tests/unit/out/unsafe/inet_pton_ntop.rs +++ b/tests/unit/out/unsafe/inet_pton_ntop.rs @@ -6,6 +6,94 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +pub unsafe fn test_s6_addr_access_0() { + let loopback: [u8; 16] = [ + 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, + 1_u8, + ]; + let mut addr: ::libc::in6_addr = unsafe { std::mem::zeroed() }; + let mut ap: *mut ::libc::in6_addr = (&mut addr as *mut ::libc::in6_addr); + { + if 16_usize != 0 { + ::std::ptr::copy_nonoverlapping( + (loopback.as_ptr() as *const ::libc::c_void), + ((*&raw mut (*&mut addr).s6_addr).as_mut_ptr() as *mut ::libc::c_void), + 16_usize as usize, + ) + } + ((*&raw mut (*&mut addr).s6_addr).as_mut_ptr() as *mut ::libc::c_void) + }; + assert!( + (((({ + let sa = core::slice::from_raw_parts( + ((*ap).__in6_u.__u6_addr8.as_mut_ptr() as *const ::libc::c_void) as *const u8, + 16_usize as usize, + ); + let sb = core::slice::from_raw_parts( + (loopback.as_ptr() as *const ::libc::c_void) as *const u8, + 16_usize as usize, + ); + let mut diff = 0_i32; + for (x, y) in sa.iter().zip(sb.iter()) { + if x != y { + diff = (*x as i32) - (*y as i32); + break; + } + } + diff + }) == (0)) as i32) + != 0) + ); + (*&raw mut (*&mut addr).s6_addr)[(0) as usize] = 32_u8; + (*&raw mut (*ap).s6_addr)[(1) as usize] = 1_u8; + assert!( + (((((((addr.__in6_u.__u6_addr8[(0) as usize] as i32) == (32)) as i32) != 0) + && (((((*ap).__in6_u.__u6_addr8[(1) as usize] as i32) == (1)) as i32) != 0)) + as i32) + != 0) + ); + (*&raw mut (*&mut addr).s6_addr)[(15) as usize] = + (((*&raw mut (*&mut addr).s6_addr)[(15) as usize] as i32) + 4) as u8; + (*&raw mut (*ap).s6_addr)[(15) as usize].postfix_inc(); + assert!(((((addr.__in6_u.__u6_addr8[(15) as usize] as i32) == (6)) as i32) != 0)); + let mut bytes: *mut u8 = (*&raw mut (*&mut addr).s6_addr).as_mut_ptr(); + (*bytes.offset((2) as isize)) = 7_u8; + assert!((((((*ap).__in6_u.__u6_addr8[(2) as usize] as i32) == (7)) as i32) != 0)); + let mut fourth: *mut u8 = (&mut (*&raw mut (*ap).s6_addr)[(3) as usize] as *mut u8); + (*fourth) = 8_u8; + assert!(((((addr.__in6_u.__u6_addr8[(3) as usize] as i32) == (8)) as i32) != 0)); + { + if 16_usize != 0 { + ::std::ptr::copy_nonoverlapping( + (loopback.as_ptr() as *const ::libc::c_void), + ((*&raw mut (*ap).s6_addr).as_mut_ptr() as *mut ::libc::c_void), + 16_usize as usize, + ) + } + ((*&raw mut (*ap).s6_addr).as_mut_ptr() as *mut ::libc::c_void) + }; + assert!( + (((({ + let sa = core::slice::from_raw_parts( + (addr.__in6_u.__u6_addr8.as_mut_ptr() as *const ::libc::c_void) as *const u8, + 16_usize as usize, + ); + let sb = core::slice::from_raw_parts( + (loopback.as_ptr() as *const ::libc::c_void) as *const u8, + 16_usize as usize, + ); + let mut diff = 0_i32; + for (x, y) in sa.iter().zip(sb.iter()) { + if x != y { + diff = (*x as i32) - (*y as i32); + break; + } + } + diff + }) == (0)) as i32) + != 0) + ); +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -13,6 +101,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { + (unsafe { test_s6_addr_access_0() }); let mut buf: [u8; 16] = [0_u8; 16]; assert!( (((({ diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index 4c46af409..dd9c2d02f 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -16,7 +16,7 @@ pub unsafe fn test_stat_0() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; assert!(((((libc::stat(path, (&mut st as *mut ::libc::stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (5_i64)) as i32) != 0)); - assert!(((((st.st_mtime) > (0_i64)) as i32) != 0)); + assert!(((((st.st_mtim.tv_sec) > (0_i64)) as i32) != 0)); libc::unlink(path); } pub unsafe fn test_fstat_1() { @@ -30,10 +30,33 @@ pub unsafe fn test_fstat_1() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; assert!(((((libc::fstat(fd, (&mut st as *mut ::libc::stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (11_i64)) as i32) != 0)); - assert!(((((st.st_mtime) > (0_i64)) as i32) != 0)); + assert!(((((st.st_mtim.tv_sec) > (0_i64)) as i32) != 0)); assert!(((((libc::fclose(fp)) == (0)) as i32) != 0)); libc::unlink(path); } +pub unsafe fn test_st_mtime_access_2() { + let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; + let mut sp: *mut ::libc::stat = (&mut st as *mut ::libc::stat); + *&raw mut (*&mut st).st_mtime = 5_i64; + assert!(((((st.st_mtim.tv_sec) == (5_i64)) as i32) != 0)); + *&raw mut (*sp).st_mtime = 6_i64; + assert!((((((*sp).st_mtim.tv_sec) == (6_i64)) as i32) != 0)); + *&raw mut (*&mut st).st_mtime += 2_i64; + assert!(((((st.st_mtim.tv_sec) == (8_i64)) as i32) != 0)); + *&raw mut (*sp).st_mtime -= 1_i64; + assert!((((((*sp).st_mtim.tv_sec) == (7_i64)) as i32) != 0)); + *&raw mut (*&mut st).st_mtime.postfix_inc(); + *&raw mut (*sp).st_mtime.prefix_inc(); + assert!(((((st.st_mtim.tv_sec) == (9_i64)) as i32) != 0)); + let mut mtime: *mut i64 = (&mut *&raw mut (*&mut st).st_mtime as *mut i64); + (*mtime) = 10_i64; + assert!(((((st.st_mtim.tv_sec) == (10_i64)) as i32) != 0)); + let mut mtime_via_ptr: *mut i64 = (&mut *&raw mut (*sp).st_mtime as *mut i64); + (*mtime_via_ptr) = 11_i64; + assert!(((((*mtime) == (11_i64)) as i32) != 0)); + let mut copy: i64 = *&raw mut (*sp).st_mtime; + assert!(((((copy) == (11_i64)) as i32) != 0)); +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -43,6 +66,7 @@ pub fn main() { unsafe fn main_0() -> i32 { (unsafe { test_stat_0() }); (unsafe { test_fstat_1() }); + (unsafe { test_st_mtime_access_2() }); return 0; } pub unsafe fn __cpp2rust_init_globals() {} From ea3c06c8da8bdd0cfcb5601b4fbd089cd6975dcb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:56:00 +0100 Subject: [PATCH 05/10] Update tests --- tests/unit/out/refcount/inet_pton_ntop.rs | 48 ++++++----------------- tests/unit/out/refcount/sys_stat.rs | 16 ++++---- tests/unit/out/unsafe/inet_pton_ntop.rs | 15 +++---- tests/unit/out/unsafe/sys_stat.rs | 16 ++++---- 4 files changed, 35 insertions(+), 60 deletions(-) diff --git a/tests/unit/out/refcount/inet_pton_ntop.rs b/tests/unit/out/refcount/inet_pton_ntop.rs index ebdcd63cb..f62541cec 100644 --- a/tests/unit/out/refcount/inet_pton_ntop.rs +++ b/tests/unit/out/refcount/inet_pton_ntop.rs @@ -23,8 +23,7 @@ pub fn test_s6_addr_access_0() { ((In6Addr::s6_addr(addr.as_pointer()) as Ptr) as Ptr).to_any() }; assert!( - (((((anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::) - as Ptr) + (((((In6Addr::s6_addr((ap).clone()) as Ptr::) as Ptr) .to_any() .memcmp( &((loopback.as_pointer() as Ptr::) as Ptr).to_any(), @@ -36,20 +35,11 @@ pub fn test_s6_addr_access_0() { elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 0).write(32_u8); elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 1).write(1_u8); assert!( - ((((((((elem!( - (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() - as Ptr::), - 0 - ) - .read()) as i32) - == 32) as i32) + ((((((((elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 0).read()) as i32) == 32) + as i32) != 0) - && (((((elem!( - (anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::), - 1 - ) - .read()) as i32) - == 1) as i32) + && (((((elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 1).read()) as i32) == 1) + as i32) != 0)) as i32) != 0) ); @@ -58,36 +48,21 @@ pub fn test_s6_addr_access_0() { }); elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 15).with_mut(|__v| __v.postfix_inc()); assert!( - (((((elem!( - (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() - as Ptr::), - 15 - ) - .read()) as i32) - == 6) as i32) + (((((elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 15).read()) as i32) == 6) + as i32) != 0) ); let mut bytes: Ptr = (In6Addr::s6_addr(addr.as_pointer()) as Ptr); elem!(bytes, 2).write(7_u8); assert!( - (((((elem!( - (anon_1::__u6_addr8(field_ptr!(ap, __in6_u)).reinterpret_cast::() as Ptr::), - 2 - ) - .read()) as i32) - == 7) as i32) + (((((elem!((In6Addr::s6_addr((ap).clone()) as Ptr::), 2).read()) as i32) == 7) as i32) != 0) ); let mut fourth: Ptr = ((In6Addr::s6_addr((ap).clone()) as Ptr).offset((3) as isize)); fourth.write(8_u8); assert!( - (((((elem!( - (anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() - as Ptr::), - 3 - ) - .read()) as i32) - == 8) as i32) + (((((elem!((In6Addr::s6_addr(addr.as_pointer()) as Ptr::), 3).read()) as i32) == 8) + as i32) != 0) ); { @@ -100,8 +75,7 @@ pub fn test_s6_addr_access_0() { ((In6Addr::s6_addr((ap).clone()) as Ptr) as Ptr).to_any() }; assert!( - (((((anon_1::__u6_addr8(field_ptr!(addr.as_pointer(), __in6_u)).reinterpret_cast::() - as Ptr::) as Ptr) + (((((In6Addr::s6_addr(addr.as_pointer()) as Ptr::) as Ptr) .to_any() .memcmp( &((loopback.as_pointer() as Ptr::) as Ptr).to_any(), diff --git a/tests/unit/out/refcount/sys_stat.rs b/tests/unit/out/refcount/sys_stat.rs index 8613c53ae..25445bb2c 100644 --- a/tests/unit/out/refcount/sys_stat.rs +++ b/tests/unit/out/refcount/sys_stat.rs @@ -45,7 +45,7 @@ pub fn test_stat_0() { != 0) ); assert!(((({ (*st.borrow()).st_size } == 5_i64) as i32) != 0)); - assert!(((({ (*st.borrow()).st_mtim.tv_sec } > 0_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) > 0_i64) as i32) != 0)); match nix::unistd::unlink(path.to_rust_string().as_str()) { Ok(()) => 0, Err(__e) => { @@ -87,7 +87,7 @@ pub fn test_fstat_1() { != 0) ); assert!(((({ (*st.borrow()).st_size } == 11_i64) as i32) != 0)); - assert!(((({ (*st.borrow()).st_mtim.tv_sec } > 0_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) > 0_i64) as i32) != 0)); assert!( ((({ let __r = fp.with(|__f| __f.close()); @@ -108,23 +108,23 @@ pub fn test_st_mtime_access_2() { let st: Value = Rc::new(RefCell::new(Default::default())); let mut sp: Ptr = (st.as_pointer()); field_ptr!(st.as_pointer(), st_mtime).write(5_i64); - assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 5_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) == 5_i64) as i32) != 0)); field_ptr!(sp, st_mtime).write(6_i64); - assert!((((sp.with(|__s| __s.st_mtim.tv_sec) == 6_i64) as i32) != 0)); + assert!(((((field_ptr!(sp, st_mtime).read()) == 6_i64) as i32) != 0)); { field_ptr!(st.as_pointer(), st_mtime).with_mut(|__v| *__v = *__v + 2_i64) }; - assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 8_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) == 8_i64) as i32) != 0)); { field_ptr!(sp, st_mtime).with_mut(|__v| *__v = *__v - 1_i64) }; - assert!((((sp.with(|__s| __s.st_mtim.tv_sec) == 7_i64) as i32) != 0)); + assert!(((((field_ptr!(sp, st_mtime).read()) == 7_i64) as i32) != 0)); field_ptr!(st.as_pointer(), st_mtime).with_mut(|__v| __v.postfix_inc()); field_ptr!(sp, st_mtime).with_mut(|__v| __v.prefix_inc()); - assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 9_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) == 9_i64) as i32) != 0)); let mut mtime: Ptr = (field_ptr!(st.as_pointer(), st_mtime)); mtime.write(10_i64); - assert!(((({ (*st.borrow()).st_mtim.tv_sec } == 10_i64) as i32) != 0)); + assert!(((((field_ptr!(st.as_pointer(), st_mtime).read()) == 10_i64) as i32) != 0)); let mut mtime_via_ptr: Ptr = (field_ptr!(sp, st_mtime)); mtime_via_ptr.write(11_i64); assert!(((((mtime.read()) == 11_i64) as i32) != 0)); diff --git a/tests/unit/out/unsafe/inet_pton_ntop.rs b/tests/unit/out/unsafe/inet_pton_ntop.rs index d830f79ff..b93e1c1cb 100644 --- a/tests/unit/out/unsafe/inet_pton_ntop.rs +++ b/tests/unit/out/unsafe/inet_pton_ntop.rs @@ -26,7 +26,7 @@ pub unsafe fn test_s6_addr_access_0() { assert!( (((({ let sa = core::slice::from_raw_parts( - ((*ap).__in6_u.__u6_addr8.as_mut_ptr() as *const ::libc::c_void) as *const u8, + ((*&raw mut (*ap).s6_addr).as_mut_ptr() as *const ::libc::c_void) as *const u8, 16_usize as usize, ); let sb = core::slice::from_raw_parts( @@ -47,21 +47,21 @@ pub unsafe fn test_s6_addr_access_0() { (*&raw mut (*&mut addr).s6_addr)[(0) as usize] = 32_u8; (*&raw mut (*ap).s6_addr)[(1) as usize] = 1_u8; assert!( - (((((((addr.__in6_u.__u6_addr8[(0) as usize] as i32) == (32)) as i32) != 0) - && (((((*ap).__in6_u.__u6_addr8[(1) as usize] as i32) == (1)) as i32) != 0)) + ((((((((*&raw mut (*&mut addr).s6_addr)[(0) as usize] as i32) == (32)) as i32) != 0) + && (((((*&raw mut (*ap).s6_addr)[(1) as usize] as i32) == (1)) as i32) != 0)) as i32) != 0) ); (*&raw mut (*&mut addr).s6_addr)[(15) as usize] = (((*&raw mut (*&mut addr).s6_addr)[(15) as usize] as i32) + 4) as u8; (*&raw mut (*ap).s6_addr)[(15) as usize].postfix_inc(); - assert!(((((addr.__in6_u.__u6_addr8[(15) as usize] as i32) == (6)) as i32) != 0)); + assert!((((((*&raw mut (*&mut addr).s6_addr)[(15) as usize] as i32) == (6)) as i32) != 0)); let mut bytes: *mut u8 = (*&raw mut (*&mut addr).s6_addr).as_mut_ptr(); (*bytes.offset((2) as isize)) = 7_u8; - assert!((((((*ap).__in6_u.__u6_addr8[(2) as usize] as i32) == (7)) as i32) != 0)); + assert!((((((*&raw mut (*ap).s6_addr)[(2) as usize] as i32) == (7)) as i32) != 0)); let mut fourth: *mut u8 = (&mut (*&raw mut (*ap).s6_addr)[(3) as usize] as *mut u8); (*fourth) = 8_u8; - assert!(((((addr.__in6_u.__u6_addr8[(3) as usize] as i32) == (8)) as i32) != 0)); + assert!((((((*&raw mut (*&mut addr).s6_addr)[(3) as usize] as i32) == (8)) as i32) != 0)); { if 16_usize != 0 { ::std::ptr::copy_nonoverlapping( @@ -75,7 +75,8 @@ pub unsafe fn test_s6_addr_access_0() { assert!( (((({ let sa = core::slice::from_raw_parts( - (addr.__in6_u.__u6_addr8.as_mut_ptr() as *const ::libc::c_void) as *const u8, + ((*&raw mut (*&mut addr).s6_addr).as_mut_ptr() as *const ::libc::c_void) + as *const u8, 16_usize as usize, ); let sb = core::slice::from_raw_parts( diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index dd9c2d02f..2fa190448 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -16,7 +16,7 @@ pub unsafe fn test_stat_0() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; assert!(((((libc::stat(path, (&mut st as *mut ::libc::stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (5_i64)) as i32) != 0)); - assert!(((((st.st_mtim.tv_sec) > (0_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) > (0_i64)) as i32) != 0)); libc::unlink(path); } pub unsafe fn test_fstat_1() { @@ -30,7 +30,7 @@ pub unsafe fn test_fstat_1() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; assert!(((((libc::fstat(fd, (&mut st as *mut ::libc::stat))) == (0)) as i32) != 0)); assert!(((((st.st_size) == (11_i64)) as i32) != 0)); - assert!(((((st.st_mtim.tv_sec) > (0_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) > (0_i64)) as i32) != 0)); assert!(((((libc::fclose(fp)) == (0)) as i32) != 0)); libc::unlink(path); } @@ -38,19 +38,19 @@ pub unsafe fn test_st_mtime_access_2() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; let mut sp: *mut ::libc::stat = (&mut st as *mut ::libc::stat); *&raw mut (*&mut st).st_mtime = 5_i64; - assert!(((((st.st_mtim.tv_sec) == (5_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) == (5_i64)) as i32) != 0)); *&raw mut (*sp).st_mtime = 6_i64; - assert!((((((*sp).st_mtim.tv_sec) == (6_i64)) as i32) != 0)); + assert!(((((*&raw mut (*sp).st_mtime) == (6_i64)) as i32) != 0)); *&raw mut (*&mut st).st_mtime += 2_i64; - assert!(((((st.st_mtim.tv_sec) == (8_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) == (8_i64)) as i32) != 0)); *&raw mut (*sp).st_mtime -= 1_i64; - assert!((((((*sp).st_mtim.tv_sec) == (7_i64)) as i32) != 0)); + assert!(((((*&raw mut (*sp).st_mtime) == (7_i64)) as i32) != 0)); *&raw mut (*&mut st).st_mtime.postfix_inc(); *&raw mut (*sp).st_mtime.prefix_inc(); - assert!(((((st.st_mtim.tv_sec) == (9_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) == (9_i64)) as i32) != 0)); let mut mtime: *mut i64 = (&mut *&raw mut (*&mut st).st_mtime as *mut i64); (*mtime) = 10_i64; - assert!(((((st.st_mtim.tv_sec) == (10_i64)) as i32) != 0)); + assert!(((((*&raw mut (*&mut st).st_mtime) == (10_i64)) as i32) != 0)); let mut mtime_via_ptr: *mut i64 = (&mut *&raw mut (*sp).st_mtime as *mut i64); (*mtime_via_ptr) = 11_i64; assert!(((((*mtime) == (11_i64)) as i32) != 0)); From 545b9f27c39e42f5b5d9ff370fcfc74cd09ded63 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 13:56:33 +0100 Subject: [PATCH 06/10] Ignore return stack address error --- rules/ip/src.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rules/ip/src.c b/rules/ip/src.c index f8073ca11..5b9fa9519 100644 --- a/rules/ip/src.c +++ b/rules/ip/src.c @@ -20,4 +20,7 @@ int f5(void) { return IPPROTO_MPTCP; } int f6(void) { return TCP_NODELAY; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-stack-address" uint8_t *f7(struct in6_addr a0) { return a0.s6_addr; } +#pragma clang diagnostic pop From 6098d439f340c59c3143b1f2131c4b815f1a3353 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 14:19:23 +0100 Subject: [PATCH 07/10] Expand macro --- cpp2rust/converter/converter.cpp | 2 +- cpp2rust/converter/rules/decls.cpp | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 3d87a0264..8b4227fd9 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3521,7 +3521,7 @@ void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { if (auto mapped = GetMappedAsString(expr); !mapped.empty()) { if (RuleRegistry::ReturnsPointer(ctx_, expr)) { - PushParen paren(*this, expr->getType()->isArrayType()); + PushParen paren(*this); StrCat(token::kStar, mapped); } else { StrCat(mapped); diff --git a/cpp2rust/converter/rules/decls.cpp b/cpp2rust/converter/rules/decls.cpp index adb551e09..c621e1d70 100644 --- a/cpp2rust/converter/rules/decls.cpp +++ b/cpp2rust/converter/rules/decls.cpp @@ -50,21 +50,27 @@ const clang::Expr *GetReturned(const clang::FunctionDecl *rule) { return returned; } +namespace { +clang::FileID getMacroExpansion(const clang::SourceManager &sm, + clang::SourceLocation loc) { + while (loc.isMacroID() && sm.isMacroArgExpansion(loc)) { + loc = sm.getImmediateSpellingLoc(loc); + } + return loc.isMacroID() ? sm.getFileID(loc) : clang::FileID(); +} +} // namespace + const clang::Expr *GetMacroMemberBase(const clang::SourceManager &sm, const clang::MemberExpr *member) { - auto loc = member->getMemberLoc(); - if (!loc.isMacroID()) { - return nullptr; - } - auto file = sm.getFileID(loc); - const auto &expansion = sm.getSLocEntry(file).getExpansion(); - if (expansion.isMacroArgExpansion() || expansion.isFunctionMacroExpansion()) { + auto file = getMacroExpansion(sm, member->getMemberLoc()); + if (file.isInvalid() || + sm.getSLocEntry(file).getExpansion().isFunctionMacroExpansion()) { return nullptr; } const clang::Expr *base = member->getBase(); while (true) { auto inner = llvm::dyn_cast(base->IgnoreParenImpCasts()); - if (!inner || sm.getFileID(inner->getMemberLoc()) != file) { + if (!inner || getMacroExpansion(sm, inner->getMemberLoc()) != file) { return base; } base = inner->getBase(); From 379f84d7cafd1b91a7f2594eb6366e15f50e9cf1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 16:12:06 +0100 Subject: [PATCH 08/10] Update tests --- tests/unit/out/unsafe/map-reallocation.rs | 4 ++-- tests/unit/out/unsafe/map.rs | 10 +++++----- .../out/unsafe/redundant_copy_in_conversion.rs | 2 +- tests/unit/out/unsafe/sys_stat.rs | 18 +++++++++--------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/unit/out/unsafe/map-reallocation.rs b/tests/unit/out/unsafe/map-reallocation.rs index b92e11deb..6e57fced7 100644 --- a/tests/unit/out/unsafe/map-reallocation.rs +++ b/tests/unit/out/unsafe/map-reallocation.rs @@ -22,7 +22,7 @@ unsafe fn main_0() -> i32 { .1) = sentinel; let mut it: UnsafeMapIterator = UnsafeMapIterator::find_key(&m as *const BTreeMap>, &sentinel); - let mut p: *mut i32 = (&mut *&raw mut (*it.deref()).1 as *mut i32); + let mut p: *mut i32 = (&mut (*&raw mut (*it.deref()).1) as *mut i32); assert!( ((*&raw mut (*it.deref()).1) == (sentinel)) && (!(c"iterator does not have correct value before insert".as_ptr()).is_null()) @@ -60,7 +60,7 @@ unsafe fn main_0() -> i32 { ((*p) == (sentinel)) && (!(c"pointer does not have correct value after insert".as_ptr()).is_null()) ); - *&raw mut (*it.deref()).1 = 57005; + (*&raw mut (*it.deref()).1) = 57005; assert!( ((*&mut m .entry(sentinel.clone()) diff --git a/tests/unit/out/unsafe/map.rs b/tests/unit/out/unsafe/map.rs index c33d763c0..23c31e12e 100644 --- a/tests/unit/out/unsafe/map.rs +++ b/tests/unit/out/unsafe/map.rs @@ -140,19 +140,19 @@ unsafe fn main_0() -> i32 { let mut x1: u32 = if it == end { 0_u32 } else { - *&raw mut (*it.deref()).1 + (*&raw mut (*it.deref()).1) }; assert!(((x1) == (4_u32))); let mut x2: u32 = if const_it == end.clone() { 0_u32 } else { - *&raw mut (*const_it.deref()).1 + (*&raw mut (*const_it.deref()).1) }; assert!(((x2) == (0_u32))); let mut x3: u32 = if it == UnsafeMapIterator::end(&m as *const BTreeMap>) { 0_u32 } else { - *&raw mut (*it.deref()).1 + (*&raw mut (*it.deref()).1) }; assert!(((x3) == (4_u32))); let mut x4: u32 = if const_it @@ -160,7 +160,7 @@ unsafe fn main_0() -> i32 { { 0_u32 } else { - *&raw mut (*const_it.deref()).1 + (*&raw mut (*const_it.deref()).1) }; assert!(((x4) == (0_u32))); (*&mut m @@ -169,7 +169,7 @@ unsafe fn main_0() -> i32 { .1) = 5_u32; let mut it4: UnsafeMapIterator = UnsafeMapIterator::find_key(&m as *const BTreeMap>, &4_i16); - let mut p: *mut u32 = (&mut *&raw mut (*it4.deref()).1 as *mut u32); + let mut p: *mut u32 = (&mut (*&raw mut (*it4.deref()).1) as *mut u32); let mut x5: u32 = (*p); assert!( ((*&mut m diff --git a/tests/unit/out/unsafe/redundant_copy_in_conversion.rs b/tests/unit/out/unsafe/redundant_copy_in_conversion.rs index 958193e7b..d83867e19 100644 --- a/tests/unit/out/unsafe/redundant_copy_in_conversion.rs +++ b/tests/unit/out/unsafe/redundant_copy_in_conversion.rs @@ -9,7 +9,7 @@ use std::rc::Rc; pub unsafe fn sink_0(mut it: UnsafeMapIterator) -> i32 { let mut cit: UnsafeMapIterator = it.clone(); return if cit == it.clone() { - *&raw mut (*it.deref()).1 + (*&raw mut (*it.deref()).1) } else { 0 }; diff --git a/tests/unit/out/unsafe/sys_stat.rs b/tests/unit/out/unsafe/sys_stat.rs index 2fa190448..507145aaf 100644 --- a/tests/unit/out/unsafe/sys_stat.rs +++ b/tests/unit/out/unsafe/sys_stat.rs @@ -37,24 +37,24 @@ pub unsafe fn test_fstat_1() { pub unsafe fn test_st_mtime_access_2() { let mut st: ::libc::stat = unsafe { std::mem::zeroed() }; let mut sp: *mut ::libc::stat = (&mut st as *mut ::libc::stat); - *&raw mut (*&mut st).st_mtime = 5_i64; + (*&raw mut (*&mut st).st_mtime) = 5_i64; assert!(((((*&raw mut (*&mut st).st_mtime) == (5_i64)) as i32) != 0)); - *&raw mut (*sp).st_mtime = 6_i64; + (*&raw mut (*sp).st_mtime) = 6_i64; assert!(((((*&raw mut (*sp).st_mtime) == (6_i64)) as i32) != 0)); - *&raw mut (*&mut st).st_mtime += 2_i64; + (*&raw mut (*&mut st).st_mtime) += 2_i64; assert!(((((*&raw mut (*&mut st).st_mtime) == (8_i64)) as i32) != 0)); - *&raw mut (*sp).st_mtime -= 1_i64; + (*&raw mut (*sp).st_mtime) -= 1_i64; assert!(((((*&raw mut (*sp).st_mtime) == (7_i64)) as i32) != 0)); - *&raw mut (*&mut st).st_mtime.postfix_inc(); - *&raw mut (*sp).st_mtime.prefix_inc(); + (*&raw mut (*&mut st).st_mtime).postfix_inc(); + (*&raw mut (*sp).st_mtime).prefix_inc(); assert!(((((*&raw mut (*&mut st).st_mtime) == (9_i64)) as i32) != 0)); - let mut mtime: *mut i64 = (&mut *&raw mut (*&mut st).st_mtime as *mut i64); + let mut mtime: *mut i64 = (&mut (*&raw mut (*&mut st).st_mtime) as *mut i64); (*mtime) = 10_i64; assert!(((((*&raw mut (*&mut st).st_mtime) == (10_i64)) as i32) != 0)); - let mut mtime_via_ptr: *mut i64 = (&mut *&raw mut (*sp).st_mtime as *mut i64); + let mut mtime_via_ptr: *mut i64 = (&mut (*&raw mut (*sp).st_mtime) as *mut i64); (*mtime_via_ptr) = 11_i64; assert!(((((*mtime) == (11_i64)) as i32) != 0)); - let mut copy: i64 = *&raw mut (*sp).st_mtime; + let mut copy: i64 = (*&raw mut (*sp).st_mtime); assert!(((((copy) == (11_i64)) as i32) != 0)); } pub fn main() { From 40947161263b1d4178267152e00e4d06b239f56b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 16:12:16 +0100 Subject: [PATCH 09/10] format --- cpp2rust/converter/converter_lib.cpp | 4 ++-- cpp2rust/converter/rules/expr_matcher.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index ec6ba73f8..21af73ae0 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1805,8 +1805,8 @@ BuildUnifiedArgs(clang::Expr *expr, clang::Expr **args, unsigned num_args) { } else if (auto *member = clang::dyn_cast(expr)) { auto *base = RuleDecls::GetMacroMemberBase( member->getMemberDecl()->getASTContext().getSourceManager(), member); - all_args.push_back(const_cast(base ? base - : member->getBase())); + all_args.push_back( + const_cast(base ? base : member->getBase())); } for (unsigned i = 0; i < num_args; ++i) { all_args.push_back(args[i]); diff --git a/cpp2rust/converter/rules/expr_matcher.cpp b/cpp2rust/converter/rules/expr_matcher.cpp index 5286a8a7f..fd7860db2 100644 --- a/cpp2rust/converter/rules/expr_matcher.cpp +++ b/cpp2rust/converter/rules/expr_matcher.cpp @@ -152,9 +152,9 @@ std::vector getOperands(clang::ASTContext &ctx, } else if (auto member = llvm::dyn_cast(expr)) { auto macro_base = RuleDecls::GetMacroMemberBase(ctx.getSourceManager(), member); - auto base = const_cast(macro_base ? macro_base - : member->getBase()) - ->IgnoreParenImpCasts(); + auto base = + const_cast(macro_base ? macro_base : member->getBase()) + ->IgnoreParenImpCasts(); if (auto arrow = llvm::dyn_cast(base); arrow && arrow->getOperator() == clang::OO_Arrow) { base = arrow->getArg(0); From a703366d8a92ec3846f85f390dad82f92372b2fd Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 15 Oct 2026 16:27:34 +0100 Subject: [PATCH 10/10] fix --- cpp2rust/converter/converter_lib.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index ce8a9e949..0216b18c7 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -28,6 +28,7 @@ #include "converter/lex.h" #include "converter/mapper.h" +#include "converter/rules/decls.h" #include "converter/rules/registry.h" // https://doc.rust-lang.org/reference/keywords.html