Skip to content

Commit e3b11db

Browse files
authored
Translate implicit casts from integer, pointer, and enum to bool (#56)
1 parent 8191b25 commit e3b11db

65 files changed

Lines changed: 1766 additions & 174 deletions

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: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -965,12 +965,8 @@ bool Converter::VisitReturnStmt(clang::ReturnStmt *stmt) {
965965
}
966966

967967
void Converter::ConvertCondition(clang::Expr *cond) {
968-
if (!cond->getType()->isBooleanType()) {
969-
PushExprKind push(*this, ExprKind::RValue);
970-
Convert(CreateConversionToBool(cond, ctx_));
971-
return;
972-
}
973-
Convert(cond);
968+
PushExprKind push(*this, ExprKind::RValue);
969+
Convert(NormalizeToBool(cond, ctx_));
974970
}
975971

976972
bool Converter::VisitIfStmt(clang::IfStmt *stmt) {
@@ -1741,6 +1737,41 @@ void Converter::ConvertIntegerToEnumeralCast(clang::Expr *to,
17411737
}
17421738
}
17431739

1740+
void Converter::ConvertIntegralToBooleanCast(clang::ImplicitCastExpr *expr) {
1741+
auto sub_expr = expr->getSubExpr();
1742+
auto *stripped = sub_expr->IgnoreParenImpCasts();
1743+
1744+
if (auto binop = clang::dyn_cast<clang::BinaryOperator>(stripped)) {
1745+
// Comparison already produces bool, no wrap needed.
1746+
if (binop->isComparisonOp()) {
1747+
Convert(sub_expr);
1748+
return;
1749+
}
1750+
// Distribute bool conversion to each argument of the logical op.
1751+
if (binop->isLogicalOp()) {
1752+
{
1753+
PushParen paren(*this);
1754+
ConvertCondition(binop->getLHS());
1755+
}
1756+
StrCat(binop->getOpcodeStr());
1757+
{
1758+
PushParen paren(*this);
1759+
ConvertCondition(binop->getRHS());
1760+
}
1761+
return;
1762+
}
1763+
}
1764+
1765+
PushParen paren(*this);
1766+
Convert(sub_expr);
1767+
StrCat(token::kDiff);
1768+
if (sub_expr->getType()->isEnumeralType()) {
1769+
StrCat(GetUnsafeTypeAsString(sub_expr->getType()), "::from(0)");
1770+
} else /* sub_expr->getType()->isIntegerType() */ {
1771+
StrCat(token::kZero);
1772+
}
1773+
}
1774+
17441775
bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
17451776
auto *sub_expr = expr->getSubExpr();
17461777
auto type = expr->getType();
@@ -1816,20 +1847,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
18161847
Convert(sub_expr);
18171848
break;
18181849
case clang::CastKind::CK_IntegralToBoolean:
1819-
if (auto binop = clang::dyn_cast<clang::BinaryOperator>(
1820-
sub_expr->IgnoreParenImpCasts())) {
1821-
// This already produces bool, no need for != 0
1822-
if (binop->isComparisonOp()) {
1823-
Convert(sub_expr);
1824-
break;
1825-
}
1826-
}
1827-
1828-
{
1829-
PushParen paren(*this);
1830-
Convert(sub_expr);
1831-
StrCat(token::kDiff, token::kZero);
1832-
}
1850+
ConvertIntegralToBooleanCast(expr);
18331851
break;
18341852
case clang::CastKind::CK_PointerToBoolean:
18351853
StrCat(token::kNot);
@@ -2130,6 +2148,18 @@ bool Converter::VisitUnaryOperator(clang::UnaryOperator *expr) {
21302148
Convert(sub_expr);
21312149
computed_expr_type_ = ComputedExprType::FreshValue;
21322150
break;
2151+
case clang::UO_LNot: {
2152+
bool needs_int_cast =
2153+
expr->getType()->isIntegerType() && !expr->getType()->isBooleanType();
2154+
PushParen paren_cast(*this, needs_int_cast);
2155+
StrCat(token::kNot);
2156+
ConvertCondition(sub_expr);
2157+
if (needs_int_cast) {
2158+
ConvertCast(expr->getType());
2159+
}
2160+
computed_expr_type_ = ComputedExprType::FreshValue;
2161+
break;
2162+
}
21332163
case clang::UO_Minus:
21342164
if (auto *literal = clang::dyn_cast<clang::IntegerLiteral>(sub_expr)) {
21352165
if (sub_expr->getType()->isUnsignedIntegerType()) {
@@ -2173,7 +2203,7 @@ void Converter::EmitStmtExprTail(clang::Expr *tail) { Convert(tail); }
21732203

21742204
bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) {
21752205
StrCat(keyword::kIf);
2176-
Convert(expr->getCond());
2206+
ConvertCondition(expr->getCond());
21772207
{
21782208
PushBrace then_brace(*this);
21792209
if (expr->isLValue() && !isRValue() && !expr->getType()->isFunctionType()) {
@@ -2290,21 +2320,11 @@ bool Converter::VisitParenExpr(clang::ParenExpr *expr) {
22902320
}
22912321
}
22922322

2293-
// Add cast to avoid ambigous integers. Don't add cast if sub expression is a
2294-
// pointer dereference because we might want to mutate the dereferenced value.
2295-
bool should_add_integral_cast =
2296-
expr->getType()->isIntegralOrEnumerationType() && !isAddrOf() &&
2297-
!isVoid() && !clang::isa<clang::UnaryOperator>(expr->getSubExpr());
2298-
PushParen outer(*this, should_add_integral_cast);
2299-
23002323
{
23012324
PushParen inner(*this);
23022325
Convert(expr->getSubExpr());
23032326
}
23042327

2305-
if (should_add_integral_cast) {
2306-
ConvertCast(expr->getType());
2307-
}
23082328
return false;
23092329
}
23102330

cpp2rust/converter/converter.h

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

244244
void ConvertIntegerToEnumeralCast(clang::Expr *to, clang::Expr *from);
245245

246+
void ConvertIntegralToBooleanCast(clang::ImplicitCastExpr *expr);
247+
246248
virtual bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr);
247249

248250
virtual bool VisitExplicitCastExpr(clang::ExplicitCastExpr *expr);

cpp2rust/converter/converter_lib.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,9 +683,32 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt) {
683683
return false;
684684
}
685685

686-
clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) {
686+
clang::Expr *NormalizeToBool(clang::Expr *expr, clang::ASTContext &ctx) {
687+
if (expr->getType()->isBooleanType()) {
688+
return expr;
689+
}
690+
691+
// If logical not returns integer, then craft a new logical not that returns
692+
// bool.
693+
if (auto bin = clang::dyn_cast<clang::UnaryOperator>(expr)) {
694+
if (bin->getOpcode() == clang::UO_LNot) {
695+
return clang::UnaryOperator::Create(
696+
ctx, bin->getSubExpr(), clang::UO_LNot, ctx.BoolTy, clang::VK_PRValue,
697+
clang::OK_Ordinary, clang::SourceLocation(), false,
698+
clang::FPOptionsOverride());
699+
}
700+
}
701+
702+
// Either to pointer -> bool, or int -> bool.
703+
clang::CastKind cast_kind;
704+
if (expr->getType()->isPointerType()) {
705+
cast_kind = clang::CK_PointerToBoolean;
706+
} else /* expr->getType()->isIntegerType() */ {
707+
cast_kind = clang::CK_IntegralToBoolean;
708+
}
709+
687710
return clang::ImplicitCastExpr::Create(
688-
ctx, ctx.BoolTy, clang::CK_IntegralToBoolean, expr,
711+
ctx, ctx.BoolTy, cast_kind, expr,
689712
/*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride());
690713
}
691714

cpp2rust/converter/converter_lib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ bool IsBuiltinVaCopy(const clang::CallExpr *expr);
154154

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

157-
clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx);
157+
clang::Expr *NormalizeToBool(clang::Expr *expr, clang::ASTContext &ctx);
158158

159159
std::vector<clang::SwitchCase *>
160160
GetTopLevelSwitchCases(clang::SwitchStmt *stmt);

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,8 @@ bool ConverterRefCount::ConvertIncAndDec(clang::UnaryOperator *expr) {
615615

616616
bool ConverterRefCount::VisitConditionalOperator(
617617
clang::ConditionalOperator *expr) {
618-
StrCat(keyword::kIf, ConvertRValue(expr->getCond()));
618+
StrCat(keyword::kIf);
619+
ConvertCondition(expr->getCond());
619620
{
620621
PushBrace then_brace(*this);
621622
StrCat(ConvertFresh(expr->getTrueExpr()));
@@ -1046,9 +1047,12 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
10461047
}
10471048
}
10481049

1049-
if (expr->getCastKind() == clang::CastKind::CK_NullToPointer &&
1050-
expr->getType()->isFunctionPointerType()) {
1051-
StrCat("FnPtr::null()");
1050+
if (expr->getCastKind() == clang::CastKind::CK_NullToPointer) {
1051+
if (expr->getType()->isFunctionPointerType()) {
1052+
StrCat("FnPtr::null()");
1053+
} else {
1054+
StrCat("Default::default()");
1055+
}
10521056
computed_expr_type_ = ComputedExprType::FreshPointer;
10531057
return false;
10541058
}
@@ -1137,6 +1141,11 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
11371141
}
11381142
return false;
11391143
}
1144+
if (expr->getCastKind() == clang::CK_NullToPointer) {
1145+
StrCat("Default::default()");
1146+
computed_expr_type_ = ComputedExprType::FreshPointer;
1147+
return false;
1148+
}
11401149
switch (expr->getStmtClass()) {
11411150
case clang::Stmt::CXXReinterpretCastExprClass:
11421151
assert(expr->getType()->isPointerType() &&

tests/ub/out/refcount/ub4.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ use std::io::{Read, Seek, Write};
77
use std::os::fd::AsFd;
88
use std::rc::{Rc, Weak};
99
pub fn smaller_0(x1: Ptr<i32>, x2: Ptr<i32>) -> Ptr<i32> {
10-
return if (({
10+
return if ({
1111
let _lhs = (x1.read());
1212
_lhs < (x2.read())
13-
}) as bool)
14-
{
13+
}) {
1514
(x1).clone()
1615
} else {
1716
(x2).clone()

tests/ub/out/unsafe/ub4.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ use std::io::{Read, Seek, Write};
77
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
88
use std::rc::Rc;
99
pub unsafe fn smaller_0(x1: *mut i32, x2: *mut i32) -> *mut i32 {
10-
return if (((*x1) < (*x2)) as bool) {
11-
(x1)
12-
} else {
13-
(x2)
14-
};
10+
return if ((*x1) < (*x2)) { (x1) } else { (x2) };
1511
}
1612
pub fn main() {
1713
unsafe {

tests/unit/bool_condition_enum.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
3+
enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 };
4+
5+
int main() {
6+
Code code = CODE_OK;
7+
Code err = CODE_ERR;
8+
9+
if (code) {
10+
assert(false);
11+
}
12+
if (!code) {
13+
assert(true);
14+
}
15+
if (err) {
16+
assert(true);
17+
}
18+
if (!err) {
19+
assert(false);
20+
}
21+
22+
int t9 = !code;
23+
assert(t9 == 1);
24+
25+
bool b4 = code;
26+
assert(!b4);
27+
28+
return 0;
29+
}

tests/unit/bool_condition_enum_c.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <assert.h>
2+
#include <stdbool.h>
3+
4+
enum Code { CODE_OK = 0, CODE_ERR = 1, CODE_FATAL = 2 };
5+
6+
int main() {
7+
enum Code code = CODE_OK;
8+
enum Code err = CODE_ERR;
9+
10+
if (code) {
11+
assert(false);
12+
}
13+
if (!code) {
14+
assert(true);
15+
}
16+
if (err) {
17+
assert(true);
18+
}
19+
if (!err) {
20+
assert(false);
21+
}
22+
23+
int t9 = !code;
24+
assert(t9 == 1);
25+
26+
bool b4 = code;
27+
assert(!b4);
28+
29+
return 0;
30+
}

tests/unit/bool_condition_int.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include <assert.h>
2+
3+
int main() {
4+
int n = 3;
5+
int zero = 0;
6+
unsigned u = 4;
7+
unsigned long ul = 5;
8+
long long ll = 6;
9+
char ch = 'a';
10+
11+
if (n) {
12+
assert(true);
13+
}
14+
if (!n) {
15+
assert(false);
16+
}
17+
if (zero) {
18+
assert(false);
19+
}
20+
if (!zero) {
21+
assert(true);
22+
}
23+
24+
if (u) {
25+
assert(true);
26+
}
27+
if (ul) {
28+
assert(true);
29+
}
30+
if (ll) {
31+
assert(true);
32+
}
33+
if (ch) {
34+
assert(true);
35+
}
36+
37+
int loop_count = 0;
38+
int counter = 3;
39+
while (counter) {
40+
--counter;
41+
++loop_count;
42+
}
43+
assert(loop_count == 3);
44+
45+
for (int i = 5; i; --i) {
46+
++loop_count;
47+
}
48+
assert(loop_count == 8);
49+
50+
int t = n ? 100 : 200;
51+
assert(t == 100);
52+
int t2 = zero ? 100 : 200;
53+
assert(t2 == 200);
54+
int t7 = !n;
55+
assert(t7 == 0);
56+
int t8 = !zero;
57+
assert(t8 == 1);
58+
59+
bool b1 = n;
60+
assert(b1);
61+
62+
return 0;
63+
}

0 commit comments

Comments
 (0)