Skip to content

Commit d0495a5

Browse files
authored
Translate C boolean expressions (#12)
In C, as opposed to C++, clang does not generate IntegerToBoolean implicit casts. To fix this, create an artificial implicit cast so that C and C++ code can be handled uniformly. As a side effect of this PR, C unit tests are now translated in C instead of C++.
1 parent cf16356 commit d0495a5

38 files changed

Lines changed: 391 additions & 43 deletions

.github/workflows/format.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
2424
2525
- name: Check C++ formatting
26-
run: find cpp2rust tests -name '*.cpp' -o -name '*.h' | xargs clang-format --dry-run --Werror
26+
run: find cpp2rust tests -name '*.cpp' -o -name '*.h' -o -name '*.c' | xargs clang-format --dry-run --Werror
2727

2828
- name: Check Rust formatting
2929
run: |

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ add_subdirectory(tests)
9393
find_program(CLANG_FORMAT NAMES clang-format-22 clang-format)
9494

9595
file(GLOB_RECURSE ALL_CXX_SOURCES
96-
cpp2rust/*.cpp cpp2rust/*.h tests/*.cpp)
96+
cpp2rust/*.cpp cpp2rust/*.h tests/*.cpp tests/*.c)
9797

9898
add_custom_target("format"
9999
COMMAND ${CLANG_FORMAT} -i ${ALL_CXX_SOURCES}

cpp2rust/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ target_link_libraries(cpp2rust PRIVATE
1313
target_include_directories(cpp2rust PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
1414
target_include_directories(cpp2rust PUBLIC SYSTEM ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS})
1515
target_compile_definitions(cpp2rust PUBLIC ${LLVM_DEFINITIONS})
16-
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_EXECUTABLE=\"${CMAKE_CXX_COMPILER}\"")
16+
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_C_COMPILER=\"${CMAKE_C_COMPILER}\"")
17+
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_CXX_COMPILER=\"${CMAKE_CXX_COMPILER}\"")
1718
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_RESOURCE_DIR=\"${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION_MAJOR}\"")
1819
target_compile_definitions(cpp2rust PUBLIC "-DCOMPAT_INCLUDE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/compat\"")
1920

cpp2rust/converter/converter.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -916,9 +916,18 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
916916
return false;
917917
}
918918

919+
void Converter::ConvertCondition(clang::Expr *cond) {
920+
if (!cond->getType()->isBooleanType()) {
921+
PushExprKind push(*this, ExprKind::RValue);
922+
Convert(CreateConversionToBool(cond, ctx_));
923+
return;
924+
}
925+
Convert(cond);
926+
}
927+
919928
bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
920929
StrCat(keyword::kIf);
921-
Convert(stmt->getCond());
930+
ConvertCondition(stmt->getCond());
922931
StrCat(token::kOpenCurlyBracket);
923932
Convert(stmt->getThen());
924933
StrCat(token::kCloseCurlyBracket);
@@ -938,7 +947,7 @@ bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
938947
bool Converter::VisitWhileStmt(clang::WhileStmt *stmt) {
939948
StrCat("'loop_:");
940949
StrCat(keyword::kWhile);
941-
Convert(stmt->getCond());
950+
ConvertCondition(stmt->getCond());
942951
StrCat(token::kOpenCurlyBracket);
943952
curr_for_inc_.emplace(nullptr);
944953
Convert(stmt->getBody());
@@ -954,7 +963,7 @@ bool Converter::VisitDoStmt(clang::DoStmt *stmt) {
954963
Convert(stmt->getBody());
955964
curr_for_inc_.pop();
956965
StrCat(keyword::kIf, token::kNot, token::kOpenParen);
957-
Convert(stmt->getCond());
966+
ConvertCondition(stmt->getCond());
958967
StrCat(token::kCloseParen, token::kOpenCurlyBracket, keyword::kBreak,
959968
token::kSemiColon, token::kCloseCurlyBracket,
960969
token::kCloseCurlyBracket);
@@ -968,7 +977,7 @@ bool Converter::VisitForStmt(clang::ForStmt *stmt) {
968977
if (stmt->getCond() == nullptr) {
969978
StrCat("true");
970979
} else {
971-
Convert(stmt->getCond());
980+
ConvertCondition(stmt->getCond());
972981
}
973982
StrCat(token::kOpenCurlyBracket);
974983
curr_for_inc_.emplace(stmt->getInc());
@@ -1546,7 +1555,8 @@ bool Converter::VisitFloatingLiteral(clang::FloatingLiteral *expr) {
15461555
bool Converter::VisitCharacterLiteral(clang::CharacterLiteral *expr) {
15471556
std::string ch = GetEscapedCharLiteral(expr->getValue());
15481557
ch = "'" + std::move(ch) + "'";
1549-
StrCat(token::kOpenParen, ch, keyword::kAs, "u8", token::kCloseParen);
1558+
StrCat(token::kOpenParen, ch, keyword::kAs, ToStringBase(expr->getType()),
1559+
token::kCloseParen);
15501560
computed_expr_type_ = ComputedExprType::FreshValue;
15511561
return false;
15521562
}
@@ -1664,6 +1674,15 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
16641674
Convert(sub_expr);
16651675
break;
16661676
case clang::CastKind::CK_IntegralToBoolean:
1677+
if (auto binop = clang::dyn_cast<clang::BinaryOperator>(
1678+
sub_expr->IgnoreParenImpCasts())) {
1679+
// This already produces bool, no need for != 0
1680+
if (binop->isComparisonOp()) {
1681+
Convert(sub_expr);
1682+
break;
1683+
}
1684+
}
1685+
16671686
StrCat(token::kOpenParen);
16681687
Convert(sub_expr);
16691688
StrCat(token::kDiff, token::kZero, token::kCloseParen);
@@ -2875,12 +2894,12 @@ void Converter::ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
28752894
curr_init_type_.pop();
28762895
auto rhs_as_string = ConvertFreshRValue(rhs);
28772896

2878-
if (isRValue()) {
2897+
if (!isVoid()) {
28792898
StrCat(token::kOpenCurlyBracket);
28802899
}
28812900

28822901
StrCat(lhs_as_string, assign_operator, rhs_as_string);
2883-
if (isRValue()) {
2902+
if (!isVoid()) {
28842903
StrCat(token::kSemiColon, ConvertRValue(lhs), token::kCloseCurlyBracket);
28852904
}
28862905
}

cpp2rust/converter/converter.h

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

113113
virtual bool VisitReturnStmt(clang::ReturnStmt *stmt);
114114

115+
void ConvertCondition(clang::Expr *cond);
116+
115117
virtual bool VisitIfStmt(clang::IfStmt *stmt);
116118

117119
virtual bool VisitWhileStmt(clang::WhileStmt *stmt);

cpp2rust/converter/converter_lib.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,4 +654,10 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt) {
654654
return false;
655655
}
656656

657+
clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) {
658+
return clang::ImplicitCastExpr::Create(
659+
ctx, ctx.BoolTy, clang::CK_IntegralToBoolean, expr,
660+
/*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride());
661+
}
662+
657663
} // namespace cpp2rust

cpp2rust/converter/converter_lib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,6 @@ bool IsBuiltinVaCopy(const clang::CallExpr *expr);
152152

153153
bool ContainsVAArgExpr(const clang::Stmt *stmt);
154154

155+
clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx);
156+
155157
} // namespace cpp2rust

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ bool ConverterRefCount::VisitPointerType(clang::PointerType *type) {
188188
PushConversionKind push2(*this, ConversionKind::FullRefCount,
189189
pointee_type->isArrayType());
190190
if (pointee_type->isRecordType() &&
191-
abstract_structs_.contains(GetID(pointee_type->getAsCXXRecordDecl()))) {
191+
abstract_structs_.contains(GetID(pointee_type->getAsRecordDecl()))) {
192192
StrCat("PtrDyn<dyn");
193193
} else {
194194
StrCat("Ptr<");

cpp2rust/cpp2rust.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ int main(int argc, char *argv[]) {
150150

151151
auto rs_code =
152152
BuildDir.empty()
153-
? cpp2rust::TranspileSrc(cc_code, model, cxx_flags, RulesDir)
153+
? cpp2rust::TranspileSrc(cc_code, model, cxx_flags, RulesDir, CcFile)
154154
: cpp2rust::TranspileDir(BuildDir, model, RulesDir);
155155

156156
if (rs_code.empty()) {

cpp2rust/cpp2rust_lib.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@
1313
namespace cpp2rust {
1414
std::string TranspileSrc(std::string_view cc_code, Model model,
1515
const std::vector<std::string_view> &cxx_flags,
16-
const std::string &rules_dir) {
16+
const std::string &rules_dir,
17+
std::string_view filename) {
1718
auto tool_args = getPlatformClangFlags();
1819
tool_args.push_back("-fparse-all-comments");
1920
tool_args.insert(tool_args.end(), cxx_flags.begin(), cxx_flags.end());
2021

2122
std::string rs_code;
2223
clang::tooling::runToolOnCodeWithArgs(
2324
std::make_unique<FrontendAction>(rs_code, model, true, rules_dir),
24-
cc_code, tool_args, "input.cpp", CLANG_EXECUTABLE);
25+
cc_code, tool_args, filename.ends_with(".c") ? "input.c" : "input.cpp",
26+
filename.ends_with(".c") ? CLANG_C_COMPILER : CLANG_CXX_COMPILER);
2527
return rs_code;
2628
}
2729

0 commit comments

Comments
 (0)