Skip to content

Commit 055988a

Browse files
committed
Merge branch 'master' into variadic-call
2 parents c4910dd + 6b0264a commit 055988a

448 files changed

Lines changed: 10033 additions & 5908 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.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ ninja check
6060
./build/cpp2rust/cpp2rust --file=<file>.cpp -o=<file>.rs
6161
```
6262

63-
By default, the reference couting model is used (fully safe output).
63+
By default, the reference counting model is used (fully safe output).
6464
To generate unsafe Rust instead:
6565

6666
```bash
@@ -128,7 +128,7 @@ ninja check-unit
128128
ninja check-libcc2rs
129129

130130
# Run libcc2rs-macros unit tests
131-
ninja check-benchmarks
131+
ninja check-libcc2rs-macros
132132

133133
# Regenerate expected output for unit tests after intentional changes
134134
REPLACE_EXPECTED=1 ninja check-unit

cmake/rust-toolchain.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
set(RUST_STABLE_VERSION "1.96.0")
2-
set(RUST_NIGHTLY_VERSION "nightly-2026-06-02")
1+
set(RUST_STABLE_VERSION "1.96.1")
2+
set(RUST_NIGHTLY_VERSION "nightly-2026-06-30")

cpp2rust/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ target_compile_definitions(cpp2rust_core PUBLIC "-DCLANG_C_COMPILER=\"${CMAKE_C_
2424
target_compile_definitions(cpp2rust_core PUBLIC "-DCLANG_CXX_COMPILER=\"${CMAKE_CXX_COMPILER}\"")
2525
target_compile_definitions(cpp2rust_core PUBLIC "-DCLANG_RESOURCE_DIR=\"${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION_MAJOR}\"")
2626
target_compile_definitions(cpp2rust_core PUBLIC "-DCOMPAT_INCLUDE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/compat\"")
27+
target_compile_definitions(cpp2rust_core PUBLIC "-DRUST_STABLE_VERSION=\"${RUST_STABLE_VERSION}\"")
2728

2829
if (APPLE)
2930
execute_process(

cpp2rust/converter/converter.cpp

Lines changed: 98 additions & 40 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:
@@ -753,6 +758,11 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
753758
}
754759
}
755760

761+
if (decl->isUnion()) {
762+
EmitRustUnion(decl);
763+
return;
764+
}
765+
756766
// Derived traits
757767
if (EmitsReprCForRecords()) {
758768
StrCat("#[repr(C)]");
@@ -770,8 +780,7 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
770780
auto access = clang::dyn_cast<clang::CXXRecordDecl>(decl)
771781
? AccessSpecifierAsString(decl->getAccess())
772782
: keyword::kPub;
773-
StrCat(access, decl->isUnion() ? keyword::kUnion : keyword::kStruct,
774-
GetRecordName(decl));
783+
StrCat(access, keyword::kStruct, GetRecordName(decl));
775784
{
776785
PushBrace brace(*this);
777786
for (auto *field : decl->fields()) {
@@ -810,9 +819,32 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
810819
// Traits
811820
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
812821
AddOrdTrait(cxx);
813-
AddCloneTrait(cxx);
814822
AddDropTrait(cxx);
815823
}
824+
AddCloneTrait(decl);
825+
AddDefaultTrait(decl);
826+
AddByteReprTrait(decl);
827+
}
828+
829+
void Converter::EmitRustUnion(clang::RecordDecl *decl) {
830+
StrCat("#[repr(C)]");
831+
auto attrs = GetStructAttributes(decl);
832+
Mapper::SetDerives(ctx_.getCanonicalTagType(decl),
833+
std::vector<std::string>(attrs.begin(), attrs.end()));
834+
StrCat("#[derive(");
835+
for (auto *attr : attrs) {
836+
StrCat(attr, ',');
837+
}
838+
StrCat(")]");
839+
840+
StrCat(keyword::kPub, keyword::kUnion, GetRecordName(decl));
841+
{
842+
PushBrace brace(*this);
843+
for (auto *field : decl->fields()) {
844+
VisitFieldDecl(field);
845+
}
846+
}
847+
816848
AddDefaultTrait(decl);
817849
AddByteReprTrait(decl);
818850
}
@@ -1383,7 +1415,8 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
13831415
} else if (arg_str.contains("Setw")) {
13841416
fmt_width = Trim(ToString(arg));
13851417
} else if (!arg->getType()->isCharType() &&
1386-
Mapper::Map(arg->getType()) != "Vec<u8>") {
1418+
Mapper::Map(arg->getType()) !=
1419+
std::format("Vec<{}>", CharRustType())) {
13871420
fmt += ("{:" + fmt_width + fmt_trait + "}");
13881421
fmt_width.clear(); // Reset setw after first usage
13891422
arg_str = ToString(arg);
@@ -1399,11 +1432,13 @@ bool Converter::GetFmtArg(clang::Expr *arg, std::string &fmt,
13991432

14001433
bool Converter::GetRawArg(clang::Expr *arg, std::string &raw_args) {
14011434
if (arg->getType()->isCharType()) {
1402-
raw_args += "(&[" + ToString(arg) + ']';
1403-
} 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())) {
14041438
PushExprKind push(*this, ExprKind::RValue);
14051439
std::string str = ToString(arg);
1406-
raw_args += "(&(" + str + ")[..(" + str + ").len() - 1]";
1440+
raw_args += "(&(" + str + ").iter().take((" + str +
1441+
").len() - 1).map(|&c| c as u8).collect::<Vec<u8>>()[..]";
14071442
} else if (Mapper::ToString(arg).contains("std::endl")) {
14081443
raw_args += "(&[b'\\n']";
14091444
} else if (clang::isa<clang::StringLiteral>(arg->IgnoreImplicit())) {
@@ -1688,6 +1723,24 @@ Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
16881723
}
16891724
}
16901725

1726+
// Inline arguments that don't alias
1727+
clang::Expr *receiver = GetCallObject(expr);
1728+
for (auto &ca : info.args) {
1729+
if (ca.kind != Kind::Hoisted) {
1730+
continue;
1731+
}
1732+
bool aliases = receiver && ArgsMayAlias(ca.expr, receiver);
1733+
for (const auto &other : info.args) {
1734+
if (&other != &ca && ArgsMayAlias(ca.expr, other.expr)) {
1735+
aliases = true;
1736+
break;
1737+
}
1738+
}
1739+
if (!aliases) {
1740+
ca.kind = Kind::Inline;
1741+
}
1742+
}
1743+
16911744
return info;
16921745
}
16931746

@@ -1824,6 +1877,14 @@ Converter::ConvertCallExpr(clang::CallExpr *expr) {
18241877
return std::nullopt;
18251878
}
18261879

1880+
static std::string getTypedLiteral(const char *num, std::string_view type) {
1881+
if (type.contains("::")) {
1882+
// Not a builtin type
1883+
return std::format("({} as {})", num, type);
1884+
}
1885+
return std::format("{}_{}", num, type);
1886+
}
1887+
18271888
std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
18281889
bool incl_type,
18291890
const clang::QualType *type) {
@@ -1845,7 +1906,7 @@ std::string Converter::getIntegerLiteral(clang::IntegerLiteral *expr,
18451906
return init;
18461907
}
18471908
}
1848-
return std::format("{}_{}", num_as_string.c_str(), type_as_string);
1909+
return getTypedLiteral(num_as_string.c_str(), type_as_string);
18491910
}
18501911

18511912
return static_cast<std::string>(num_as_string);
@@ -1938,19 +1999,30 @@ bool Converter::VisitStringLiteral(clang::StringLiteral *expr) {
19381999
if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.back())) {
19392000
uint64_t arr_size = arr_ty->getSize().getZExtValue();
19402001
if (expr->getString().empty()) {
1941-
StrCat(std::format("[0u8; {}]", arr_size));
2002+
StrCat(std::format("[0 as libc::c_char; {}]", arr_size));
19422003
return false;
19432004
}
19442005
uint64_t pad = arr_size > expr->getString().size()
19452006
? arr_size - expr->getString().size()
19462007
: 0;
1947-
StrCat(token::kStar,
1948-
std::format("b{}", GetEscapedStringLiteral(expr, pad)));
2008+
StrCat(std::format("std::mem::transmute(*b{})",
2009+
GetEscapedStringLiteral(expr, pad)));
19492010
return false;
19502011
}
1951-
StrCat(token::kStar);
2012+
StrCat(std::format("std::mem::transmute(*b{})",
2013+
GetEscapedStringLiteral(expr, 1)));
2014+
return false;
2015+
}
2016+
if (expr->getString().contains('\0')) {
2017+
std::string out = "(&[";
2018+
for (unsigned char c : expr->getString()) {
2019+
out += getTypedLiteral(std::to_string(c).c_str(), CharRustType()) + ", ";
2020+
}
2021+
out += getTypedLiteral("0", CharRustType()) + "])";
2022+
StrCat(out);
2023+
return false;
19522024
}
1953-
StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 1)));
2025+
StrCat(std::format("c{}", GetEscapedStringLiteral(expr, 0)));
19542026
return false;
19552027
}
19562028

@@ -2033,15 +2105,6 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
20332105
}
20342106
bool dest_pointee_const =
20352107
expr->getType()->getPointeeType().isConstQualified();
2036-
if (const auto *member =
2037-
clang::dyn_cast<clang::MemberExpr>(sub_expr->IgnoreParenImpCasts());
2038-
member && IsCharArrayFieldFromLibc(member->getMemberDecl())) {
2039-
PushParen paren(*this);
2040-
Convert(sub_expr);
2041-
StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()");
2042-
StrCat(keyword::kAs, dest_pointee_const ? "*const u8" : "*mut u8");
2043-
break;
2044-
}
20452108
Convert(sub_expr);
20462109
if (clang::isa<clang::StringLiteral>(sub_expr) ||
20472110
clang::isa<clang::PredefinedExpr>(sub_expr)) {
@@ -2233,7 +2296,8 @@ void Converter::ConvertBinaryOperator(clang::BinaryOperator *expr) {
22332296
if (auto *cmpd_assign_op =
22342297
llvm::dyn_cast<clang::CompoundAssignOperator>(expr);
22352298
expr->isCompoundAssignmentOp() &&
2236-
lhs_type != cmpd_assign_op->getComputationResultType()) {
2299+
GetUnsafeTypeAsString(lhs_type) !=
2300+
GetUnsafeTypeAsString(cmpd_assign_op->getComputationResultType())) {
22372301
auto computation_result_type = cmpd_assign_op->getComputationResultType();
22382302
if (IsUnsignedArithOp(cmpd_assign_op)) {
22392303
Convert(lhs);
@@ -2257,7 +2321,7 @@ void Converter::ConvertBinaryOperator(clang::BinaryOperator *expr) {
22572321
auto op = opcode_as_string;
22582322
op.remove_suffix(1); // remove '=' from operator
22592323
StrCat(op);
2260-
Convert(rhs);
2324+
Convert(rhs, computation_result_type);
22612325
}
22622326
if (lhs_type->isBooleanType()) {
22632327
StrCat(token::kDiff, token::kZero);
@@ -2729,16 +2793,6 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) {
27292793
return false;
27302794
}
27312795

2732-
// char* fields in libc structs are *mut i8. We represent char* as *mut u8. Do
2733-
// the i8 -> u8 conversion here.
2734-
if (IsCharPointerFieldFromLibc(member)) {
2735-
StrCat(std::format("({} as {})", str,
2736-
member->getType()->getPointeeType().isConstQualified()
2737-
? "*const u8"
2738-
: "*mut u8"));
2739-
return false;
2740-
}
2741-
27422796
StrCat(str);
27432797
return false;
27442798
}
@@ -2903,7 +2957,8 @@ bool Converter::VisitCompoundLiteralExpr(clang::CompoundLiteralExpr *expr) {
29032957

29042958
bool Converter::VisitArraySubscriptExpr(clang::ArraySubscriptExpr *expr) {
29052959
auto *base = expr->getBase();
2906-
if (base->IgnoreCasts()->getType()->isPointerType()) {
2960+
if (base->IgnoreCasts()->getType()->isPointerType() ||
2961+
clang::isa<clang::StringLiteral>(base->IgnoreCasts())) {
29072962
ConvertPointerSubscript(expr);
29082963
} else {
29092964
ConvertArraySubscript(base, expr->getIdx(), expr->getType());
@@ -3158,6 +3213,7 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) {
31583213

31593214
AddFromImpl(decl);
31603215
AddIncDecImpls(decl);
3216+
AddByteReprTrait(decl);
31613217
return false;
31623218
}
31633219

@@ -3438,11 +3494,11 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) {
34383494
}
34393495

34403496
if (qual_type->isIntegerType() && !qual_type->isEnumeralType()) {
3441-
return std::format("0_{}", ToString(qual_type));
3497+
return getTypedLiteral("0", ToString(qual_type));
34423498
}
34433499

34443500
if (qual_type->isFloatingType()) {
3445-
return std::format("0.0_{}", ToString(qual_type));
3501+
return getTypedLiteral("0.0", ToString(qual_type));
34463502
}
34473503

34483504
if (auto record = qual_type->getAsRecordDecl();
@@ -3757,7 +3813,7 @@ void Converter::ConvertFunctionMain(const clang::FunctionDecl *decl,
37573813
pub fn main() {{
37583814
let mut args: Vec<Vec<u8>> = std::env::args().map(|arg| arg.as_bytes().to_vec()).collect();
37593815
args.iter_mut().for_each(|v| v.push(0));
3760-
let mut argv: Vec<*mut u8> = args.iter().map(|arg| arg.as_ptr() as *mut u8).collect();
3816+
let mut argv: Vec<*mut libc::c_char> = args.iter().map(|arg| arg.as_ptr() as *mut libc::c_char).collect();
37613817
argv.push(::std::ptr::null_mut());
37623818
unsafe {{
37633819
::std::process::exit(main_0((argv.len() - 1) as i32, argv.as_mut_ptr()) as i32)
@@ -3881,7 +3937,7 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) {
38813937
ConvertOrdAndPartialOrdTraits(decl, methods[0]);
38823938
}
38833939

3884-
void Converter::AddCloneTrait(const clang::CXXRecordDecl *decl) {}
3940+
void Converter::AddCloneTrait(const clang::RecordDecl *decl) {}
38853941

38863942
void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {}
38873943

@@ -3940,6 +3996,8 @@ void Converter::EmitDefaultStructLiteral(const clang::RecordDecl *decl) {
39403996

39413997
void Converter::AddByteReprTrait(const clang::RecordDecl *decl) {}
39423998

3999+
void Converter::AddByteReprTrait(const clang::EnumDecl *decl) {}
4000+
39434001
void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op,
39444002
clang::Expr *expr) {
39454003
StrCat(token::kDot);

cpp2rust/converter/converter.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,12 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
112112

113113
virtual void EmitRustStructOrUnion(clang::RecordDecl *decl);
114114

115+
virtual void EmitRustUnion(clang::RecordDecl *decl);
116+
115117
virtual bool EmitsReprCForRecords() const { return true; }
116118

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

@@ -528,7 +532,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
528532
std::string_view second_return,
529533
std::string_view record_name);
530534

531-
virtual void AddCloneTrait(const clang::CXXRecordDecl *decl);
535+
virtual void AddCloneTrait(const clang::RecordDecl *decl);
532536

533537
virtual void AddDropTrait(const clang::CXXRecordDecl *decl);
534538

@@ -540,6 +544,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
540544

541545
virtual void AddByteReprTrait(const clang::RecordDecl *decl);
542546

547+
virtual void AddByteReprTrait(const clang::EnumDecl *decl);
548+
543549
virtual void
544550
ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *binary_operator,
545551
clang::Expr *expr);

0 commit comments

Comments
 (0)