Skip to content
Draft
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
65 changes: 32 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("core::ffi::c_char");
break;
case clang::BuiltinType::SChar:
StrCat("i8");
break;
case clang::BuiltinType::UChar:
StrCat("u8");
break;
case clang::BuiltinType::UShort:
Expand Down Expand Up @@ -1374,7 +1379,7 @@ 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()) != "Vec<core::ffi::c_char>") {
fmt += ("{:" + fmt_width + fmt_trait + "}");
fmt_width.clear(); // Reset setw after first usage
arg_str = ToString(arg);
Expand All @@ -1390,11 +1395,12 @@ 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()) == "Vec<core::ffi::c_char>") {
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 @@ -1793,6 +1799,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 @@ -1814,7 +1828,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 @@ -1907,19 +1921,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 core::ffi::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("libcc2rs::char_array(b{})",
GetEscapedStringLiteral(expr, pad)));
return false;
}
StrCat(token::kStar);
StrCat(std::format("libcc2rs::char_array(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 @@ -2002,15 +2020,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 @@ -2698,16 +2707,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 @@ -3399,11 +3398,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 @@ -3718,7 +3717,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 core::ffi::c_char> = args.iter().map(|arg| arg.as_ptr() as *mut core::ffi::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
20 changes: 0 additions & 20 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,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 @@ -39,10 +39,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
2 changes: 1 addition & 1 deletion cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ void addBuiltinTypes(Model model) {
}

// Char
add_builtin_rule(ctx_->CharTy, "u8");
add_builtin_rule(ctx_->CharTy, "core::ffi::c_char");
add_builtin_rule(ctx_->SignedCharTy, "i8");
add_builtin_rule(ctx_->UnsignedCharTy, "u8");

Expand Down
40 changes: 28 additions & 12 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 @@ -1036,14 +1037,15 @@ bool ConverterRefCount::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("vec![0u8; {}].into_boxed_slice()", arr_size));
StrCat(std::format(
"vec![0 as core::ffi::c_char; {}].into_boxed_slice()", arr_size));
return false;
}
pad = arr_size > expr->getString().size()
? arr_size - expr->getString().size()
: 0;
}
StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())",
StrCat(std::format("Box::from(libcc2rs::char_array(b{}))",
GetEscapedStringLiteral(expr, pad)));
return false;
}
Expand Down Expand Up @@ -1241,8 +1243,13 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
expr->getType()->isPointerType()) {
Convert(expr->getSubExpr());
PushConversionKind push(*this, ConversionKind::Unboxed);
StrCat(std::format(".cast::<{}>().expect(\"ub:wrong type\")",
ConvertPointeeType(expr->getType())));
if (expr->getType()->getPointeeType()->isCharType()) {
StrCat(std::format(".reinterpret_cast::<{}>()",
ConvertPointeeType(expr->getType())));
} else {
StrCat(std::format(".cast::<{}>().expect(\"ub:wrong type\")",
ConvertPointeeType(expr->getType())));
}
return false;
} else if (expr->getType()->isVoidPointerType() &&
expr->getSubExpr()->getType()->isPointerType()) {
Expand All @@ -1253,9 +1260,18 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
} else if (expr->getSubExpr()->getType()->isPointerType() &&
!expr->getSubExpr()->isNullPointerConstant(
ctx_, clang::Expr::NPC_ValueDependentIsNull)) {
StrCat(std::format("({}.to_strong().as_pointer() as {})",
ToString(expr->getSubExpr()),
ToString(expr->getType())));
auto src_type = ToString(expr->getSubExpr()->getType());
auto tgt_type = ToString(expr->getType());
if (src_type == tgt_type) {
StrCat(std::format("({}.to_strong().as_pointer() as {})",
ToString(expr->getSubExpr()), tgt_type));
} else {
PushConversionKind push(*this, ConversionKind::Unboxed);
StrCat(std::format(
"({}.to_strong().as_pointer() as {}).reinterpret_cast::<{}>()",
ToString(expr->getSubExpr()), src_type,
ConvertPointeeType(expr->getType())));
}
return false;
}
return Converter::VisitExplicitCastExpr(expr);
Expand Down Expand Up @@ -2082,7 +2098,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
void ConverterRefCount::ConvertFunctionParameters(clang::FunctionDecl *decl) {
PushConversionKind push(*this, ConversionKind::Unboxed);
if (decl->isMain() && (decl->getNumParams() != 0U)) {
StrCat(std::format("{}: i32, {}: Ptr<Ptr<u8>>",
StrCat(std::format("{}: i32, {}: Ptr<Ptr<core::ffi::c_char>>",
GetNamedDeclAsString(decl->getParamDecl(0)),
GetNamedDeclAsString(decl->getParamDecl(1))));
} else {
Expand Down Expand Up @@ -2165,10 +2181,10 @@ void ConverterRefCount::ConvertFunctionMain(
if (decl->getNumParams() != 0U) {
StrCat(std::format(R"(
pub fn main() {{
let argv: Vec<Value<Vec<u8>>> = ::std::env::args()
.map(|x| Rc::new(RefCell::new(x.as_bytes().to_vec())))
let argv: Vec<Value<Vec<core::ffi::c_char>>> = ::std::env::args()
.map(|x| Rc::new(RefCell::new(x.bytes().map(|b| b as core::ffi::c_char).collect())))
.collect();
let mut argv: Value<Vec<Ptr<u8>>> = Rc::new(RefCell::new(
let mut argv: Value<Vec<Ptr<core::ffi::c_char>>> = Rc::new(RefCell::new(
argv.iter().map(|x| {{ x.borrow_mut().push(0); x.as_pointer() }}).collect(),
));
(*argv.borrow_mut()).push(Ptr::null());
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 core::ffi::c_char) -> *mut core::ffi::c_char {
unsafe { libc::strdup(a0) }
}
10 changes: 2 additions & 8 deletions libcc2rs/src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ pub unsafe fn cerr_unsafe() -> *mut std::fs::File {

pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
let total = a1.saturating_mul(a2);
let mut dst = a0
.cast::<u8>()
.expect("fread: only supporting u8 pointers")
.clone();
let mut dst = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
Expand Down Expand Up @@ -123,10 +120,7 @@ pub fn fread_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>

pub fn fwrite_refcount(a0: AnyPtr, a1: usize, a2: usize, a3: Ptr<::std::fs::File>) -> usize {
let total = a1.saturating_mul(a2);
let mut src = a0
.cast::<u8>()
.expect("fwrite: only supporting u8 pointers")
.clone();
let mut src = a0.reinterpret_cast::<u8>();

let f = (*a3.upgrade().deref())
.try_clone()
Expand Down
10 changes: 10 additions & 0 deletions libcc2rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,13 @@ mod va_args;
pub use va_args::*;

pub use libcc2rs_macros::{goto, goto_block, switch};

pub const fn char_array<const N: usize>(s: &[u8; N]) -> [core::ffi::c_char; N] {
let mut out = [0 as core::ffi::c_char; N];
let mut i = 0;
while i < N {
out[i] = s[i] as core::ffi::c_char;
i += 1;
}
out
}
Loading
Loading