Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
echo "$HOME/.cargo/bin" >> $GITHUB_PATH

- name: Check C++ formatting
run: find cpp2rust tests -name '*.cpp' -o -name '*.h' | xargs clang-format --dry-run --Werror
run: find cpp2rust tests -name '*.cpp' -o -name '*.h' -o -name '*.c' | xargs clang-format --dry-run --Werror

- name: Check Rust formatting
run: |
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ add_subdirectory(tests)
find_program(CLANG_FORMAT NAMES clang-format-22 clang-format)

file(GLOB_RECURSE ALL_CXX_SOURCES
cpp2rust/*.cpp cpp2rust/*.h tests/*.cpp)
cpp2rust/*.cpp cpp2rust/*.h tests/*.cpp tests/*.c)

add_custom_target("format"
COMMAND ${CLANG_FORMAT} -i ${ALL_CXX_SOURCES}
Expand Down
3 changes: 2 additions & 1 deletion cpp2rust/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ target_link_libraries(cpp2rust PRIVATE
target_include_directories(cpp2rust PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(cpp2rust PUBLIC SYSTEM ${CLANG_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS})
target_compile_definitions(cpp2rust PUBLIC ${LLVM_DEFINITIONS})
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_EXECUTABLE=\"${CMAKE_CXX_COMPILER}\"")
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_C_COMPILER=\"${CMAKE_C_COMPILER}\"")
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_CXX_COMPILER=\"${CMAKE_CXX_COMPILER}\"")
target_compile_definitions(cpp2rust PUBLIC "-DCLANG_RESOURCE_DIR=\"${LLVM_LIBRARY_DIR}/clang/${LLVM_VERSION_MAJOR}\"")
target_compile_definitions(cpp2rust PUBLIC "-DCOMPAT_INCLUDE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/compat\"")

Expand Down
33 changes: 26 additions & 7 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -916,9 +916,18 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
return false;
}

void Converter::ConvertCondition(clang::Expr *cond) {
if (!cond->getType()->isBooleanType()) {
PushExprKind push(*this, ExprKind::RValue);
Convert(CreateConversionToBool(cond, ctx_));
return;
}
Convert(cond);
}

bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
StrCat(keyword::kIf);
Convert(stmt->getCond());
ConvertCondition(stmt->getCond());
StrCat(token::kOpenCurlyBracket);
Convert(stmt->getThen());
StrCat(token::kCloseCurlyBracket);
Expand All @@ -938,7 +947,7 @@ bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
bool Converter::VisitWhileStmt(clang::WhileStmt *stmt) {
StrCat("'loop_:");
StrCat(keyword::kWhile);
Convert(stmt->getCond());
ConvertCondition(stmt->getCond());
StrCat(token::kOpenCurlyBracket);
curr_for_inc_.emplace(nullptr);
Convert(stmt->getBody());
Expand All @@ -954,7 +963,7 @@ bool Converter::VisitDoStmt(clang::DoStmt *stmt) {
Convert(stmt->getBody());
curr_for_inc_.pop();
StrCat(keyword::kIf, token::kNot, token::kOpenParen);
Convert(stmt->getCond());
ConvertCondition(stmt->getCond());
StrCat(token::kCloseParen, token::kOpenCurlyBracket, keyword::kBreak,
token::kSemiColon, token::kCloseCurlyBracket,
token::kCloseCurlyBracket);
Expand All @@ -968,7 +977,7 @@ bool Converter::VisitForStmt(clang::ForStmt *stmt) {
if (stmt->getCond() == nullptr) {
StrCat("true");
} else {
Convert(stmt->getCond());
ConvertCondition(stmt->getCond());
}
StrCat(token::kOpenCurlyBracket);
curr_for_inc_.emplace(stmt->getInc());
Expand Down Expand Up @@ -1546,7 +1555,8 @@ bool Converter::VisitFloatingLiteral(clang::FloatingLiteral *expr) {
bool Converter::VisitCharacterLiteral(clang::CharacterLiteral *expr) {
std::string ch = GetEscapedCharLiteral(expr->getValue());
ch = "'" + std::move(ch) + "'";
StrCat(token::kOpenParen, ch, keyword::kAs, "u8", token::kCloseParen);
StrCat(token::kOpenParen, ch, keyword::kAs, ToStringBase(expr->getType()),
token::kCloseParen);
computed_expr_type_ = ComputedExprType::FreshValue;
return false;
}
Expand Down Expand Up @@ -1664,6 +1674,15 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
Convert(sub_expr);
break;
case clang::CastKind::CK_IntegralToBoolean:
if (auto binop = clang::dyn_cast<clang::BinaryOperator>(
sub_expr->IgnoreParenImpCasts())) {
// This already produces bool, no need for != 0
if (binop->isComparisonOp()) {
Convert(sub_expr);
break;
}
}

StrCat(token::kOpenParen);
Convert(sub_expr);
StrCat(token::kDiff, token::kZero, token::kCloseParen);
Expand Down Expand Up @@ -2875,12 +2894,12 @@ void Converter::ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs,
curr_init_type_.pop();
auto rhs_as_string = ConvertFreshRValue(rhs);

if (isRValue()) {
if (!isVoid()) {
StrCat(token::kOpenCurlyBracket);
}

StrCat(lhs_as_string, assign_operator, rhs_as_string);
if (isRValue()) {
if (!isVoid()) {
StrCat(token::kSemiColon, ConvertRValue(lhs), token::kCloseCurlyBracket);
}
}
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

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

void ConvertCondition(clang::Expr *cond);

virtual bool VisitIfStmt(clang::IfStmt *stmt);

virtual bool VisitWhileStmt(clang::WhileStmt *stmt);
Expand Down
6 changes: 6 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,4 +654,10 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt) {
return false;
}

clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) {
return clang::ImplicitCastExpr::Create(
ctx, ctx.BoolTy, clang::CK_IntegralToBoolean, expr,
/*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride());
}

} // namespace cpp2rust
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,6 @@ bool IsBuiltinVaCopy(const clang::CallExpr *expr);

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

clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx);

} // namespace cpp2rust
2 changes: 1 addition & 1 deletion cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ bool ConverterRefCount::VisitPointerType(clang::PointerType *type) {
PushConversionKind push2(*this, ConversionKind::FullRefCount,
pointee_type->isArrayType());
if (pointee_type->isRecordType() &&
abstract_structs_.contains(GetID(pointee_type->getAsCXXRecordDecl()))) {
abstract_structs_.contains(GetID(pointee_type->getAsRecordDecl()))) {
StrCat("PtrDyn<dyn");
} else {
StrCat("Ptr<");
Expand Down
2 changes: 1 addition & 1 deletion cpp2rust/cpp2rust.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ int main(int argc, char *argv[]) {

auto rs_code =
BuildDir.empty()
? cpp2rust::TranspileSrc(cc_code, model, cxx_flags, RulesDir)
? cpp2rust::TranspileSrc(cc_code, model, cxx_flags, RulesDir, CcFile)
: cpp2rust::TranspileDir(BuildDir, model, RulesDir);

if (rs_code.empty()) {
Expand Down
6 changes: 4 additions & 2 deletions cpp2rust/cpp2rust_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
namespace cpp2rust {
std::string TranspileSrc(std::string_view cc_code, Model model,
const std::vector<std::string_view> &cxx_flags,
const std::string &rules_dir) {
const std::string &rules_dir,
std::string_view filename) {
auto tool_args = getPlatformClangFlags();
tool_args.push_back("-fparse-all-comments");
tool_args.insert(tool_args.end(), cxx_flags.begin(), cxx_flags.end());

std::string rs_code;
clang::tooling::runToolOnCodeWithArgs(
std::make_unique<FrontendAction>(rs_code, model, true, rules_dir),
cc_code, tool_args, "input.cpp", CLANG_EXECUTABLE);
cc_code, tool_args, filename.ends_with(".c") ? "input.c" : "input.cpp",
filename.ends_with(".c") ? CLANG_C_COMPILER : CLANG_CXX_COMPILER);
return rs_code;
}

Expand Down
3 changes: 2 additions & 1 deletion cpp2rust/cpp2rust_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace cpp2rust {

std::string TranspileSrc(std::string_view cc_code, Model model,
const std::vector<std::string_view> &cxx_flags,
const std::string &rules_dir);
const std::string &rules_dir,
std::string_view filename);
std::string TranspileDir(std::string_view build_dir, Model model,
const std::string &rules_dir);

Expand Down
7 changes: 4 additions & 3 deletions tests/lit/lit/formats/Cpp2RustTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def getTestsInDirectory(self, testSuite, path_in_suite,
litConfig, localConfig):
source_path = testSuite.getSourcePath(path_in_suite)
for filename in os.listdir(source_path):
if filename.endswith('.cpp'):
if filename.endswith('.cpp') or filename.endswith('.c'):
for t in self.getTestsForPath(testSuite, path_in_suite + (filename,), litConfig, localConfig):
yield t

Expand Down Expand Up @@ -172,10 +172,11 @@ def fail(str, code = fail_code):
elif is_nondet_result:
lit.util.executeCommand(rust_bin)
else:
cmd = ['clang++', '-O3', '-o', tmp_dir + '/cpp', cc_input]
cc = 'clang' if cc_input.endswith('.c') else 'clang++'
cmd = [cc, '-O3', '-o', tmp_dir + '/cpp', cc_input]
_, _, code = lit.util.executeCommand(cmd)
if code != 0:
return fail('clang++ failed')
return fail(cc + ' failed')

out_cpp, err_cpp, code_cpp = lit.util.executeCommand(tmp_dir + '/cpp')
out_rs, err_rs, code_rs = lit.util.executeCommand(rust_bin)
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/expr_as_bool_c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <assert.h>
#include <stdbool.h>

int main() {
int a = 0;
int b;

if (b = a) {
}
while ((b = a) != 0) {
}
if (a) {
}
if (a == b) {
}
if (a < b) {
}

assert(a == b);
assert(!(a = b));

bool c;
c = a = b;
c = (b = a) != 0;
c = a;
c = a == b;
c = a < b;
return 0;
}
29 changes: 29 additions & 0 deletions tests/unit/expr_as_bool_cpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include <assert.h>
#include <stdbool.h>

int main() {
int a = 0;
int b;

if (b = a) {
}
while ((b = a) != 0) {
}
if (a) {
}
if (a == b) {
}
if (a < b) {
}

assert(a == b);
assert(!(a = b));

bool c;
c = a = b;
c = (b = a) != 0;
c = a;
c = a == b;
c = a < b;
return 0;
}
22 changes: 22 additions & 0 deletions tests/unit/out/refcount/expr_as_bool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::Seek;
use std::io::{Read, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let a: Value<i32> = Rc::new(RefCell::new(0));
let b: Value<i32> = <Value<i32>>::default();
if ({
(*b.borrow_mut()) = (*a.borrow());
(*b.borrow())
} != 0)
{}
return 0;
}
52 changes: 52 additions & 0 deletions tests/unit/out/refcount/expr_as_bool_c.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::Seek;
use std::io::{Read, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let a: Value<i32> = Rc::new(RefCell::new(0));
let b: Value<i32> = <Value<i32>>::default();
if ({
(*b.borrow_mut()) = (*a.borrow());
(*b.borrow())
} != 0)
{}
'loop_: while ((({
(*b.borrow_mut()) = (*a.borrow());
(*b.borrow())
}) as i32)
!= 0)
{}
if ((*a.borrow()) != 0) {}
if ((*a.borrow()) == (*b.borrow())) {}
if ((*a.borrow()) < (*b.borrow())) {}
assert!(((*a.borrow()) == (*b.borrow())));
assert!(
(!(({
(*a.borrow_mut()) = (*b.borrow());
(*a.borrow())
}) as i32)
!= 0)
);
let c: Value<bool> = <Value<bool>>::default();
(*c.borrow_mut()) = ({
(*a.borrow_mut()) = (*b.borrow());
(*a.borrow())
} != 0);
(*c.borrow_mut()) = ((({
(*b.borrow_mut()) = (*a.borrow());
(*b.borrow())
}) as i32)
!= 0);
(*c.borrow_mut()) = ((*a.borrow()) != 0);
(*c.borrow_mut()) = ((*a.borrow()) == (*b.borrow()));
(*c.borrow_mut()) = ((*a.borrow()) < (*b.borrow()));
return 0;
}
Loading
Loading