Skip to content

Commit 1b372c1

Browse files
authored
Translate char as libc::c_char in unsafe (#194)
Translates char as c_char instead of u8 in both unsafe. Refcount is unchanged. This contains: 1. change all unsafe rules to use c_char instead of u8 2. use c_char instead of u8 in mapper and VisitBuiltinType 3. use c_char in argv for both unsafe 4. delete the IsCharPointerFieldFromLibc and IsCharArrayFieldFromLibc hacks 5. use the edition 2024 `c""` syntax to define c_char compatible string literals 6. use getTypedLiteral to write `0 as c_char` (correct) instead of `0_c_char` (incorrect) The big advantage of this PR is 4. IsCharPointerFieldFromLibc and IsCharArrayFieldFromLibc were temporary solutions to interact between our u8 and libc's c_char. After this PR, both functions are deleted.
1 parent c94254d commit 1b372c1

116 files changed

Lines changed: 1543 additions & 1489 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cpp2rust/converter/converter.cpp

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,13 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) {
123123
StrCat("f64");
124124
break;
125125
case clang::BuiltinType::Char_S:
126-
case clang::BuiltinType::UChar:
126+
case clang::BuiltinType::Char_U:
127+
StrCat(CharRustType());
128+
break;
127129
case clang::BuiltinType::SChar:
130+
StrCat("i8");
131+
break;
132+
case clang::BuiltinType::UChar:
128133
StrCat("u8");
129134
break;
130135
case clang::BuiltinType::UShort:
@@ -1410,7 +1415,8 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
14101415
} else if (arg_str.contains("Setw")) {
14111416
fmt_width = Trim(ToString(arg));
14121417
} else if (!arg->getType()->isCharType() &&
1413-
Mapper::Map(arg->getType()) != "Vec<u8>") {
1418+
Mapper::Map(arg->getType()) !=
1419+
std::format("Vec<{}>", CharRustType())) {
14141420
fmt += ("{:" + fmt_width + fmt_trait + "}");
14151421
fmt_width.clear(); // Reset setw after first usage
14161422
arg_str = ToString(arg);
@@ -1426,11 +1432,13 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
14261432

14271433
bool Converter::GetRawArg(clang::Expr *arg, std::string &raw_args) {
14281434
if (arg->getType()->isCharType()) {
1429-
raw_args += "(&[" + ToString(arg) + ']';
1430-
} else if (Mapper::Map(arg->getType()) == "Vec<u8>") {
1435+
raw_args += "(&[" + ToString(arg) + " as u8]";
1436+
} else if (Mapper::Map(arg->getType()) ==
1437+
std::format("Vec<{}>", CharRustType())) {
14311438
PushExprKind push(*this, ExprKind::RValue);
14321439
std::string str = ToString(arg);
1433-
raw_args += "(&(" + str + ")[..(" + str + ").len() - 1]";
1440+
raw_args += "(&(" + str + ").iter().take((" + str +
1441+
").len() - 1).map(|&c| c as u8).collect::<Vec<u8>>()[..]";
14341442
} else if (Mapper::ToString(arg).contains("std::endl")) {
14351443
raw_args += "(&[b'\\n']";
14361444
} else if (clang::isa<clang::StringLiteral>(arg->IgnoreImplicit())) {
@@ -1847,6 +1855,14 @@ Converter::ConvertCallExpr(clang::CallExpr *expr) {
18471855
return std::nullopt;
18481856
}
18491857

1858+
static std::string getTypedLiteral(const char *num, std::string_view type) {
1859+
if (type.contains("::")) {
1860+
// Not a builtin type
1861+
return std::format("({} as {})", num, type);
1862+
}
1863+
return std::format("{}_{}", num, type);
1864+
}
1865+
18501866
std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
18511867
bool incl_type,
18521868
const clang::QualType *type) {
@@ -1868,7 +1884,7 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
18681884
return init;
18691885
}
18701886
}
1871-
return std::format("{}_{}", num_as_string.c_str(), type_as_string);
1887+
return getTypedLiteral(num_as_string.c_str(), type_as_string);
18721888
}
18731889

18741890
return static_cast<std::string>(num_as_string);
@@ -1961,19 +1977,23 @@ bool Converter::VisitStringLiteral(clang::StringLiteral *expr) {
19611977
if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.back())) {
19621978
uint64_t arr_size = arr_ty->getSize().getZExtValue();
19631979
if (expr->getString().empty()) {
1964-
StrCat(std::format("[0u8; {}]", arr_size));
1980+
StrCat(std::format("[0 as libc::c_char; {}]", arr_size));
19651981
return false;
19661982
}
19671983
uint64_t pad = arr_size > expr->getString().size()
19681984
? arr_size - expr->getString().size()
19691985
: 0;
1970-
StrCat(token::kStar,
1971-
std::format("b{}", GetEscapedStringLiteral(expr, pad)));
1986+
StrCat(std::format("std::mem::transmute(*b{})",
1987+
GetEscapedStringLiteral(expr, pad)));
19721988
return false;
19731989
}
1974-
StrCat(token::kStar);
1990+
StrCat(std::format("std::mem::transmute(*b{})",
1991+
GetEscapedStringLiteral(expr, 1)));
1992+
return false;
19751993
}
1976-
StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 1)));
1994+
assert(!expr->getString().contains('\0') &&
1995+
"interior null byte in string literal");
1996+
StrCat(std::format("c{}", GetEscapedStringLiteral(expr, 0)));
19771997
return false;
19781998
}
19791999

@@ -2056,15 +2076,6 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
20562076
}
20572077
bool dest_pointee_const =
20582078
expr->getType()->getPointeeType().isConstQualified();
2059-
if (const auto *member =
2060-
clang::dyn_cast<clang::MemberExpr>(sub_expr->IgnoreParenImpCasts());
2061-
member && IsCharArrayFieldFromLibc(member->getMemberDecl())) {
2062-
PushParen paren(*this);
2063-
Convert(sub_expr);
2064-
StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()");
2065-
StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8");
2066-
break;
2067-
}
20682079
Convert(sub_expr);
20692080
if (clang::isa<clang::StringLiteral>(sub_expr) ||
20702081
clang::isa<clang::PredefinedExpr>(sub_expr)) {
@@ -2752,16 +2763,6 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
27522763
return false;
27532764
}
27542765

2755-
// char* fields in libc structs are *mut i8. We represent char* as *mut u8. Do
2756-
// the i8 -> u8 conversion here.
2757-
if (IsCharPointerFieldFromLibc(member)) {
2758-
StrCat(std::format("({} as {})", str,
2759-
member->getType()->getPointeeType().isConstQualified()
2760-
? "*const u8"
2761-
: "*mut u8"));
2762-
return false;
2763-
}
2764-
27652766
StrCat(str);
27662767
return false;
27672768
}
@@ -3462,11 +3463,11 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) {
34623463
}
34633464

34643465
if (qual_type->isIntegerType() && !qual_type->isEnumeralType()) {
3465-
return std::format("0_{}", ToString(qual_type));
3466+
return getTypedLiteral("0", ToString(qual_type));
34663467
}
34673468

34683469
if (qual_type->isFloatingType()) {
3469-
return std::format("0.0_{}", ToString(qual_type));
3470+
return getTypedLiteral("0.0", ToString(qual_type));
34703471
}
34713472

34723473
if (auto record = qual_type->getAsRecordDecl();
@@ -3781,7 +3782,7 @@ void Converter::ConvertFunctionMain(const clang::FunctionDecl *decl,
37813782
pub fn main() {{
37823783
let mut args: Vec<Vec<u8>> = std::env::args().map(|arg| arg.as_bytes().to_vec()).collect();
37833784
args.iter_mut().for_each(|v| v.push(0));
3784-
let mut argv: Vec<*mut u8> = args.iter().map(|arg| arg.as_ptr() as *mut u8).collect();
3785+
let mut argv: Vec<*mut libc::c_char> = args.iter().map(|arg| arg.as_ptr() as *mut libc::c_char).collect();
37853786
argv.push(::std::ptr::null_mut());
37863787
unsafe {{
37873788
::std::process::exit(main_0((argv.len() - 1) as i32, argv.as_mut_ptr()) as i32)

cpp2rust/converter/converter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
116116

117117
virtual bool EmitsReprCForRecords() const { return true; }
118118

119+
virtual const char *CharRustType() const { return "libc::c_char"; }
120+
119121
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl);
120122
virtual std::string GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl);
121123

cpp2rust/converter/converter_lib.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -130,26 +130,6 @@ bool IsInMainFile(const clang::Decl *decl) {
130130
return src_mgr.isInMainFile(src_mgr.getExpansionLoc(loc));
131131
}
132132

133-
bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl) {
134-
auto field = clang::dyn_cast<clang::FieldDecl>(decl);
135-
if (!field || !field->getType()->isPointerType() ||
136-
!field->getType()->getPointeeType()->isCharType()) {
137-
return false;
138-
}
139-
return field->getASTContext().getSourceManager().isInSystemHeader(
140-
field->getParent()->getLocation());
141-
}
142-
143-
bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl) {
144-
auto field = clang::dyn_cast<clang::FieldDecl>(decl);
145-
if (!field || !field->getType()->isArrayType() ||
146-
!field->getType()->getArrayElementTypeNoTypeQual()->isCharType()) {
147-
return false;
148-
}
149-
return field->getASTContext().getSourceManager().isInSystemHeader(
150-
field->getParent()->getLocation());
151-
}
152-
153133
bool IsUserDefinedDecl(const clang::Decl *decl) {
154134
const auto &ctx = decl->getASTContext();
155135
const auto &src_mgr = ctx.getSourceManager();

cpp2rust/converter/converter_lib.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,6 @@ bool IsComparisonWithNullOp(const clang::BinaryOperator *expr);
4040

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

43-
bool IsCharPointerFieldFromLibc(const clang::ValueDecl *decl);
44-
45-
bool IsCharArrayFieldFromLibc(const clang::ValueDecl *decl);
46-
4743
bool IsUserDefinedDecl(const clang::Decl *decl);
4844

4945
bool RefersToUserDefinedDecl(const clang::Expr *expr);

cpp2rust/converter/mapper.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,14 @@ void addBuiltinTypes(Model model) {
530530
}
531531

532532
// Char
533-
add_builtin_rule(ctx_->CharTy, "u8");
533+
switch (model) {
534+
case Model::kUnsafe:
535+
add_builtin_rule(ctx_->CharTy, "libc::c_char");
536+
break;
537+
case Model::kRefCount:
538+
add_builtin_rule(ctx_->CharTy, "u8");
539+
break;
540+
}
534541
add_builtin_rule(ctx_->SignedCharTy, "i8");
535542
add_builtin_rule(ctx_->UnsignedCharTy, "u8");
536543

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,8 @@ std::string ConverterRefCount::BuildFnAdapter(
211211
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
212212
ConvertPointeeType(src_pty));
213213
} else if (src_pty->getPointeeType()->isCharType()) {
214-
closure += std::format("a{}.reinterpret_cast::<u8>()", i);
214+
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
215+
ConvertPointeeType(src_pty));
215216
}
216217
} else {
217218
// UB: Incompatible types
@@ -1103,8 +1104,7 @@ bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) {
11031104
? arr_size - expr->getString().size()
11041105
: 0;
11051106
}
1106-
StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())",
1107-
GetEscapedStringLiteral(expr, pad)));
1107+
StrCat(std::format("Box::from(*b{})", GetEscapedStringLiteral(expr, pad)));
11081108
return false;
11091109
}
11101110
StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 0)));

cpp2rust/converter/models/converter_refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ConverterRefCount final : public Converter {
3232

3333
bool EmitsReprCForRecords() const override { return false; }
3434

35+
const char *CharRustType() const override { return "u8"; }
36+
3537
void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
3638
const clang::FunctionDecl *op) override;
3739

cpp2rust/cpp2rust.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ int main(int argc, char *argv[]) {
190190
file.close();
191191

192192
// call rustfmt.
193-
std::string rustfmt_command = "rustfmt " + RsFile;
193+
std::string rustfmt_command = "rustfmt --edition 2024 " + RsFile;
194194
if (std::system(rustfmt_command.c_str()) != 0) {
195195
llvm::errs() << "ERROR: failed to run rustfmt\n";
196196
return EXIT_FAILURE;

libcc2rs/src/alloc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ pub unsafe fn calloc_unsafe(a0: usize, a1: usize) -> *mut libc::c_void {
3232
/// # Safety
3333
///
3434
/// Same contract as C's `strdup`.
35-
pub unsafe fn strdup_unsafe(a0: *const u8) -> *mut u8 {
36-
unsafe { libc::strdup(a0 as *const libc::c_char) as *mut u8 }
35+
pub unsafe fn strdup_unsafe(a0: *const libc::c_char) -> *mut libc::c_char {
36+
unsafe { libc::strdup(a0) }
3737
}

rules/algorithm/tgt_unsafe.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ unsafe fn f12<T1: Clone>(a0: *mut T1, a1: *mut T1, a2: T1) {
101101
std::slice::from_raw_parts_mut(a0, count).fill(a2)
102102
}
103103

104-
unsafe fn f13(a0: *const u8, a1: *const u8, a2: &mut ::std::fs::File) -> ::std::fs::File {
104+
unsafe fn f13(
105+
a0: *const libc::c_char,
106+
a1: *const libc::c_char,
107+
a2: &mut ::std::fs::File,
108+
) -> ::std::fs::File {
105109
let __start = a0 as *const u8;
106110
let __end = a1 as *const u8;
107111
let __len = __end.offset_from(__start) as usize;

0 commit comments

Comments
 (0)