Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
0dca34e
Use C size when size_of diverges between C and Rust
lucic71 Jun 24, 2026
8fa8bec
Add byte_size in ByteRepr to capture C size
lucic71 Jun 24, 2026
a07a40f
Delete unused function
lucic71 Jun 25, 2026
7db5002
Add correct from_bytes type
lucic71 Jun 25, 2026
c66a712
Update tests
lucic71 Jun 25, 2026
5af65da
Add panic default implementations
lucic71 Jun 25, 2026
8084fc9
Implement byte_size for primitives
lucic71 Jun 25, 2026
532c0b5
Allow enums to have byterepr
lucic71 Jun 25, 2026
0573f9c
Don't add ByteRepr for system header types
lucic71 Jun 25, 2026
32d916a
Ignore unions in ByteRepr for now
lucic71 Jun 25, 2026
96cd270
Update tests
lucic71 Jun 25, 2026
3402042
Memcpy a poitner to a struct through ErasedPtr
lucic71 Jun 23, 2026
fb7f030
Add memcpy_struct_bytes test
lucic71 Jun 25, 2026
e4bb83e
Update tests
lucic71 Jun 25, 2026
d979745
Merge branch 'master' into anyptr-reinterpreted
lucic71 Jun 29, 2026
48d6908
Trigger CI
lucic71 Jun 29, 2026
3436b46
Merge branch 'master' into anyptr-reinterpreted
lucic71 Jun 29, 2026
658b9ed
Use reinterpret_cast to round-trip through void
lucic71 Jul 1, 2026
ba3fd40
Update tests
lucic71 Jul 1, 2026
93681bd
clang-format
lucic71 Jul 1, 2026
70bf770
Fix expected output
lucic71 Jul 1, 2026
b1705c3
Merge branch 'master' into void-round-trip
lucic71 Jul 1, 2026
dd22145
Merge branch 'fix-union' into void-round-trip
lucic71 Jul 1, 2026
cde0270
Update tests
lucic71 Jul 1, 2026
2b7953e
Merge branch 'master' into void-round-trip
lucic71 Jul 1, 2026
fb91acc
Update tests
lucic71 Jul 1, 2026
ce013d3
Update tests
lucic71 Jun 13, 2026
7191bfc
Use c_char instead of u8
lucic71 Jun 13, 2026
479fd65
Use c_char in libcc2rs mapped rules
lucic71 Jun 13, 2026
10d5e7d
Use c_char for cstrings in libcc2rs
lucic71 Jun 13, 2026
73a73ce
Use edition 2024 for rustfmt
lucic71 Jun 13, 2026
65fd796
Use c_char instead of u8 for char translation
lucic71 Jun 13, 2026
6116b5c
Delete IsCharPointerFieldFromLibc and IsCharArrayFieldFromLibc
lucic71 Jun 13, 2026
8169cb7
Fix building of argv
lucic71 Jun 13, 2026
97cbfa6
Fix 0 initialization for c_char
lucic71 Jun 13, 2026
7050c08
Fix implicit and explicit casts between u8/c_char
lucic71 Jun 13, 2026
6098f86
Fix definition of main to use c_char
lucic71 Jun 13, 2026
6d0a3e9
Convert Vec<c_char> to Vec<u8> when printing
lucic71 Jun 13, 2026
7206596
Fix char array initialization to use c_char
lucic71 Jun 13, 2026
cbcbf3d
Add libcc2rs::char_array to initialize fixed sized arrays
lucic71 Jun 13, 2026
470fc0e
cargo gmt
lucic71 Jun 13, 2026
fff36f8
Snapshot/write-back the entire region between offset and end of origi…
lucic71 Jun 13, 2026
d28f225
Replace ::core::ffi::c_char with core::ffi::c_char
lucic71 Jun 13, 2026
0962678
Merge branch 'void-round-trip' into u8-as-c_char
lucic71 Jul 1, 2026
455df3c
Use CharRustType() between unsafe and refcoutn
lucic71 Jul 1, 2026
068573a
Fix argv for unsafe and refcount
lucic71 Jul 1, 2026
85c0c13
Update tests
lucic71 Jul 1, 2026
0f3d428
Use c_char in unsafe and u8 in refcount
lucic71 Jul 1, 2026
f299656
Fix merge artifact
lucic71 Jul 1, 2026
49bea74
Use u8 in rc.rs
lucic71 Jul 1, 2026
574ecf0
Use c_char in unsafe and u8 in refcount
lucic71 Jul 1, 2026
d9499af
Delete libcc2rs::char_array
lucic71 Jul 1, 2026
3bb2814
Update tests
lucic71 Jul 1, 2026
3e71cd3
Delete useless cast form rule
lucic71 Jul 1, 2026
2e89ab2
Delete separate Ptr impl for u8
lucic71 Jul 1, 2026
7830f8a
Drop unsafe from transmute
lucic71 Jul 1, 2026
503ea51
Use c_char in unsafe
lucic71 Jul 1, 2026
e5356d0
Update tests
lucic71 Jul 1, 2026
0904ff6
Add safe rules using u8 instead of c_char
lucic71 Jul 1, 2026
b8ead47
Merge branch 'master' into u8-as-c_char
lucic71 Jul 1, 2026
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
67 changes: 34 additions & 33 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,13 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) {
StrCat("f64");
break;
case clang::BuiltinType::Char_S:
case clang::BuiltinType::UChar:
case clang::BuiltinType::Char_U:
StrCat(CharRustType());
break;
case clang::BuiltinType::SChar:
StrCat("i8");
break;
case clang::BuiltinType::UChar:
StrCat("u8");
break;
case clang::BuiltinType::UShort:
Expand Down Expand Up @@ -1410,7 +1415,8 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
} else if (arg_str.contains("Setw")) {
fmt_width = Trim(ToString(arg));
} else if (!arg->getType()->isCharType() &&
Mapper::Map(arg->getType()) != "Vec<u8>") {
Mapper::Map(arg->getType()) !=
std::format("Vec<{}>", CharRustType())) {
fmt += ("{:" + fmt_width + fmt_trait + "}");
fmt_width.clear(); // Reset setw after first usage
arg_str = ToString(arg);
Expand All @@ -1426,11 +1432,13 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,

bool Converter::GetRawArg(clang::Expr *arg, std::string &raw_args) {
if (arg->getType()->isCharType()) {
raw_args += "(&[" + ToString(arg) + ']';
} else if (Mapper::Map(arg->getType()) == "Vec<u8>") {
raw_args += "(&[" + ToString(arg) + " as u8]";
} else if (Mapper::Map(arg->getType()) ==
std::format("Vec<{}>", CharRustType())) {
PushExprKind push(*this, ExprKind::RValue);
std::string str = ToString(arg);
raw_args += "(&(" + str + ")[..(" + str + ").len() - 1]";
raw_args += "(&(" + str + ").iter().take((" + str +
").len() - 1).map(|&c| c as u8).collect::<Vec<u8>>()[..]";
} else if (Mapper::ToString(arg).contains("std::endl")) {
raw_args += "(&[b'\\n']";
} else if (clang::isa<clang::StringLiteral>(arg->IgnoreImplicit())) {
Expand Down Expand Up @@ -1847,6 +1855,14 @@ Converter::ConvertCallExpr(clang::CallExpr *expr) {
return std::nullopt;
}

static std::string getTypedLiteral(const char *num, std::string_view type) {
if (type.contains("::")) {
// Not a builtin type
return std::format("({} as {})", num, type);
}
return std::format("{}_{}", num, type);
}

std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
bool incl_type,
const clang::QualType *type) {
Expand All @@ -1868,7 +1884,7 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
return init;
}
}
return std::format("{}_{}", num_as_string.c_str(), type_as_string);
return getTypedLiteral(num_as_string.c_str(), type_as_string);
}

return static_cast<std::string>(num_as_string);
Expand Down Expand Up @@ -1961,19 +1977,23 @@ bool Converter::VisitStringLiteral(clang::StringLiteral *expr) {
if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.back())) {
uint64_t arr_size = arr_ty->getSize().getZExtValue();
if (expr->getString().empty()) {
StrCat(std::format("[0u8; {}]", arr_size));
StrCat(std::format("[0 as libc::c_char; {}]", arr_size));
return false;
}
uint64_t pad = arr_size > expr->getString().size()
? arr_size - expr->getString().size()
: 0;
StrCat(token::kStar,
std::format("b{}", GetEscapedStringLiteral(expr, pad)));
StrCat(std::format("std::mem::transmute(*b{})",
GetEscapedStringLiteral(expr, pad)));
return false;
}
StrCat(token::kStar);
StrCat(std::format("std::mem::transmute(*b{})",
GetEscapedStringLiteral(expr, 1)));
return false;
}
StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 1)));
assert(!expr->getString().contains('\0') &&
"interior null byte in string literal");
StrCat(std::format("c{}", GetEscapedStringLiteral(expr, 0)));
return false;
}

Expand Down Expand Up @@ -2056,15 +2076,6 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
}
bool dest_pointee_const =
expr->getType()->getPointeeType().isConstQualified();
if (const auto *member =
clang::dyn_cast<clang::MemberExpr>(sub_expr->IgnoreParenImpCasts());
member && IsCharArrayFieldFromLibc(member->getMemberDecl())) {
PushParen paren(*this);
Convert(sub_expr);
StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()");
StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8");
break;
}
Convert(sub_expr);
if (clang::isa<clang::StringLiteral>(sub_expr) ||
clang::isa<clang::PredefinedExpr>(sub_expr)) {
Expand Down Expand Up @@ -2752,16 +2763,6 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
return false;
}

// char* fields in libc structs are *mut i8. We represent char* as *mut u8. Do
// the i8 -> u8 conversion here.
if (IsCharPointerFieldFromLibc(member)) {
StrCat(std::format("({} as {})", str,
member->getType()->getPointeeType().isConstQualified()
? "*const u8"
: "*mut u8"));
return false;
}

StrCat(str);
return false;
}
Expand Down Expand Up @@ -3462,11 +3463,11 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) {
}

if (qual_type->isIntegerType() && !qual_type->isEnumeralType()) {
return std::format("0_{}", ToString(qual_type));
return getTypedLiteral("0", ToString(qual_type));
}

if (qual_type->isFloatingType()) {
return std::format("0.0_{}", ToString(qual_type));
return getTypedLiteral("0.0", ToString(qual_type));
}

if (auto record = qual_type->getAsRecordDecl();
Expand Down Expand Up @@ -3781,7 +3782,7 @@ void Converter::ConvertFunctionMain(const clang::FunctionDecl *decl,
pub fn main() {{
let mut args: Vec<Vec<u8>> = std::env::args().map(|arg| arg.as_bytes().to_vec()).collect();
args.iter_mut().for_each(|v| v.push(0));
let mut argv: Vec<*mut u8> = args.iter().map(|arg| arg.as_ptr() as *mut u8).collect();
let mut argv: Vec<*mut libc::c_char> = args.iter().map(|arg| arg.as_ptr() as *mut libc::c_char).collect();
argv.push(::std::ptr::null_mut());
unsafe {{
::std::process::exit(main_0((argv.len() - 1) as i32, argv.as_mut_ptr()) as i32)
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual bool EmitsReprCForRecords() const { return true; }

virtual const char *CharRustType() const { return "libc::c_char"; }

virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl);
virtual std::string GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl);

Expand Down
20 changes: 0 additions & 20 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,26 +130,6 @@ bool IsInMainFile(const clang::Decl *decl) {
return src_mgr.isInMainFile(src_mgr.getExpansionLoc(loc));
}

bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl) {
auto field = clang::dyn_cast<clang::FieldDecl>(decl);
if (!field || !field->getType()->isPointerType() ||
!field->getType()->getPointeeType()->isCharType()) {
return false;
}
return field->getASTContext().getSourceManager().isInSystemHeader(
field->getParent()->getLocation());
}

bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl) {
auto field = clang::dyn_cast<clang::FieldDecl>(decl);
if (!field || !field->getType()->isArrayType() ||
!field->getType()->getArrayElementTypeNoTypeQual()->isCharType()) {
return false;
}
return field->getASTContext().getSourceManager().isInSystemHeader(
field->getParent()->getLocation());
}

bool IsUserDefinedDecl(const clang::Decl *decl) {
const auto &ctx = decl->getASTContext();
const auto &src_mgr = ctx.getSourceManager();
Expand Down
4 changes: 0 additions & 4 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ bool IsComparisonWithNullOp(const clang::BinaryOperator *expr);

bool IsInMainFile(const clang::Decl *decl);

bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl);

bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl);

bool IsUserDefinedDecl(const clang::Decl *decl);

bool RefersToUserDefinedDecl(const clang::Expr *expr);
Expand Down
9 changes: 8 additions & 1 deletion cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,14 @@ void addBuiltinTypes(Model model) {
}

// Char
add_builtin_rule(ctx_->CharTy, "u8");
switch (model) {
case Model::kUnsafe:
add_builtin_rule(ctx_->CharTy, "libc::c_char");
break;
case Model::kRefCount:
add_builtin_rule(ctx_->CharTy, "u8");
break;
}
add_builtin_rule(ctx_->SignedCharTy, "i8");
add_builtin_rule(ctx_->UnsignedCharTy, "u8");

Expand Down
6 changes: 3 additions & 3 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ std::string ConverterRefCount::BuildFnAdapter(
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
ConvertPointeeType(src_pty));
} else if (src_pty->getPointeeType()->isCharType()) {
closure += std::format("a{}.reinterpret_cast::<u8>()", i);
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
ConvertPointeeType(src_pty));
}
} else {
// UB: Incompatible types
Expand Down Expand Up @@ -1103,8 +1104,7 @@ bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) {
? arr_size - expr->getString().size()
: 0;
}
StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())",
GetEscapedStringLiteral(expr, pad)));
StrCat(std::format("Box::from(*b{})", GetEscapedStringLiteral(expr, pad)));
return false;
}
StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 0)));
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class ConverterRefCount final : public Converter {

bool EmitsReprCForRecords() const override { return false; }

const char *CharRustType() const override { return "u8"; }

void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
const clang::FunctionDecl *op) override;

Expand Down
2 changes: 1 addition & 1 deletion cpp2rust/cpp2rust.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) {
file.close();

// call rustfmt.
std::string rustfmt_command = "rustfmt " + RsFile;
std::string rustfmt_command = "rustfmt --edition 2024 " + RsFile;
if (std::system(rustfmt_command.c_str()) != 0) {
llvm::errs() << "ERROR: failed to run rustfmt\n";
return EXIT_FAILURE;
Expand Down
4 changes: 2 additions & 2 deletions libcc2rs/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ pub unsafe fn calloc_unsafe(a0: usize, a1: usize) -> *mut libc::c_void {
/// # Safety
///
/// Same contract as C's `strdup`.
pub unsafe fn strdup_unsafe(a0: *const u8) -> *mut u8 {
unsafe { libc::strdup(a0 as *const libc::c_char) as *mut u8 }
pub unsafe fn strdup_unsafe(a0: *const libc::c_char) -> *mut libc::c_char {
unsafe { libc::strdup(a0) }
}
6 changes: 5 additions & 1 deletion rules/algorithm/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ unsafe fn f12<T1: Clone>(a0: *mut T1, a1: *mut T1, a2: T1) {
std::slice::from_raw_parts_mut(a0, count).fill(a2)
}

unsafe fn f13(a0: *const u8, a1: *const u8, a2: &mut ::std::fs::File) -> ::std::fs::File {
unsafe fn f13(
a0: *const libc::c_char,
a1: *const libc::c_char,
a2: &mut ::std::fs::File,
) -> ::std::fs::File {
let __start = a0 as *const u8;
let __end = a1 as *const u8;
let __len = __end.offset_from(__start) as usize;
Expand Down
18 changes: 14 additions & 4 deletions rules/arpa_inet/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,25 @@ unsafe fn f3(a0: u16) -> u16 {
unsafe fn f4(a0: u32) -> u32 {
u32::to_be(a0)
}
unsafe fn f5(a0: i32, a1: *const u8, a2: *mut ::libc::c_void) -> i32 {
unsafe fn f5(a0: i32, a1: *const libc::c_char, a2: *mut ::libc::c_void) -> i32 {
unsafe extern "C" {
fn inet_pton(af: i32, src: *const u8, dst: *mut ::libc::c_void) -> i32;
fn inet_pton(af: i32, src: *const libc::c_char, dst: *mut ::libc::c_void) -> i32;
}
inet_pton(a0, a1, a2)
}
unsafe fn f6(a0: i32, a1: *const ::libc::c_void, a2: *mut u8, a3: u32) -> *const u8 {
unsafe fn f6(
a0: i32,
a1: *const ::libc::c_void,
a2: *mut libc::c_char,
a3: u32,
) -> *const libc::c_char {
unsafe extern "C" {
fn inet_ntop(af: i32, src: *const ::libc::c_void, dst: *mut u8, size: u32) -> *const u8;
fn inet_ntop(
af: i32,
src: *const ::libc::c_void,
dst: *mut libc::c_char,
size: u32,
) -> *const libc::c_char;
}
inet_ntop(a0, a1, a2, a3)
}
12 changes: 6 additions & 6 deletions rules/cstdlib/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ unsafe fn f5(a0: usize, a1: usize) -> *mut ::libc::c_void {
libcc2rs::calloc_unsafe(a0, a1)
}

unsafe fn f6(a0: *const u8) -> *mut u8 {
libc::getenv(a0 as *const i8) as *mut u8
unsafe fn f6(a0: *const libc::c_char) -> *mut libc::c_char {
libc::getenv(a0)
}

unsafe fn f7(a0: *const u8, a1: *const u8, a2: i32) -> i32 {
libc::setenv(a0 as *const i8, a1 as *const i8, a2)
unsafe fn f7(a0: *const libc::c_char, a1: *const libc::c_char, a2: i32) -> i32 {
libc::setenv(a0, a1, a2)
}

unsafe fn f8(
Expand Down Expand Up @@ -65,6 +65,6 @@ unsafe fn f9(
)
}

unsafe fn f10(a0: *const u8, a1: *mut u8) -> *mut u8 {
libc::realpath(a0 as *const i8, a1 as *mut i8) as *mut u8
unsafe fn f10(a0: *const libc::c_char, a1: *mut libc::c_char) -> *mut libc::c_char {
libc::realpath(a0, a1)
}
Loading
Loading