commit baaef7ed977a8c3d5df2aef673185101abc381d4 (tree)
parent bf678a12dfbdf0b3bb50804aa6b7ee081013049a
Author: Andrew Kelley <andrew@ziglang.org>
Date: Mon, 6 Jan 2020 19:21:55 -0500
Merge pull request #4083 from LemonBoy/better-stdbool
Better _Bool translation
Diffstat:
6 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig
@@ -805,6 +805,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str
pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;
+pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType;
pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType;
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
@@ -1285,7 +1285,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
try transExprCoercing(rp, scope, expr, .used, .r_value)
else
try transCreateNodeUndefinedLiteral(c);
- if (isBoolRes(init_node)) {
+ if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
try builtin_node.params.push(init_node);
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
@@ -1351,9 +1351,13 @@ fn transImplicitCastExpr(
return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false);
},
.IntegralToBoolean => {
- // val != 0
const node = try transExpr(rp, scope, sub_expr, .used, .r_value);
+ // The expression is already a boolean one, return it as-is
+ if (isBoolRes(node))
+ return node;
+
+ // val != 0
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, result_used, false);
@@ -1409,6 +1413,10 @@ fn transBoolExpr(
}
}
+fn exprIsBooleanType(expr: *const ZigClangExpr) bool {
+ return qualTypeIsBoolean(ZigClangExpr_getType(expr));
+}
+
fn isBoolRes(res: *ast.Node) bool {
switch (res.id) {
.InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
@@ -1738,6 +1746,14 @@ fn transCCast(
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return &builtin_node.base;
}
+ if (ZigClangType_isBooleanType(qualTypeCanon(src_type)) and
+ !ZigClangType_isBooleanType(qualTypeCanon(dst_type)))
+ {
+ const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
+ try builtin_node.params.push(expr);
+ builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
+ return &builtin_node.base;
+ }
if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) {
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum");
try builtin_node.params.push(try transQualType(rp, dst_type, loc));
@@ -3089,6 +3105,10 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
}
+fn qualTypeIsBoolean(qt: ZigClangQualType) bool {
+ return ZigClangType_isBooleanType(qualTypeCanon(qt));
+}
+
fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 {
const ty = ZigClangQualType_getTypePtr(qt);
@@ -3365,7 +3385,7 @@ fn transCreateNodeAssign(
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
const eq_token = try appendToken(rp.c, .Equal, "=");
var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
- if (isBoolRes(rhs_node)) {
+ if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
try builtin_node.params.push(rhs_node);
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
@@ -3390,7 +3410,7 @@ fn transCreateNodeAssign(
const node = try transCreateNodeVarDecl(rp.c, false, true, tmp);
node.eq_token = try appendToken(rp.c, .Equal, "=");
var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
- if (isBoolRes(rhs_node)) {
+ if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
try builtin_node.params.push(rhs_node);
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
@@ -1814,6 +1814,11 @@ ZigClangQualType ZigClangType_getPointeeType(const ZigClangType *self) {
return bitcast(casted->getPointeeType());
}
+bool ZigClangType_isBooleanType(const ZigClangType *self) {
+ auto casted = reinterpret_cast<const clang::Type *>(self);
+ return casted->isBooleanType();
+}
+
bool ZigClangType_isVoidType(const ZigClangType *self) {
auto casted = reinterpret_cast<const clang::Type *>(self);
return casted->isVoidType();
diff --git a/src/zig_clang.h b/src/zig_clang.h
@@ -932,6 +932,7 @@ ZIG_EXTERN_C bool ZigClangQualType_isRestrictQualified(struct ZigClangQualType);
ZIG_EXTERN_C enum ZigClangTypeClass ZigClangType_getTypeClass(const struct ZigClangType *self);
ZIG_EXTERN_C struct ZigClangQualType ZigClangType_getPointeeType(const struct ZigClangType *self);
+ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig
@@ -3,6 +3,23 @@ const tests = @import("tests.zig");
const nl = std.cstr.line_sep;
pub fn addCases(cases: *tests.RunTranslatedCContext) void {
+ cases.add("boolean values and expressions",
+ \\#include <stdlib.h>
+ \\static const _Bool false_val = 0;
+ \\static const _Bool true_val = 1;
+ \\void foo(int x, int y) {
+ \\ _Bool r = x < y;
+ \\ if (!r) abort();
+ \\ _Bool self = foo;
+ \\ if (self == false_val) abort();
+ \\}
+ \\int main(int argc, char **argv) {
+ \\ foo(2, 5);
+ \\ if (false_val == true_val) abort();
+ \\ return 0;
+ \\}
+ , "");
+
cases.add("hello world",
\\#define _NO_CRT_STDIO_INLINE 1
\\#include <stdio.h>
diff --git a/test/translate_c.zig b/test/translate_c.zig
@@ -2504,4 +2504,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ foo(@intToPtr([*c]c_int, @ptrToInt(a)));
\\}
});
+
+ cases.add("handling of _Bool type",
+ \\_Bool foo(_Bool x) {
+ \\ _Bool a = x != 1;
+ \\ _Bool b = a != 0;
+ \\ _Bool c = foo;
+ \\ return foo(c != b);
+ \\}
+ , &[_][]const u8{
+ \\pub export fn foo(arg_x: bool) bool {
+ \\ var x = arg_x;
+ \\ var a: bool = (@boolToInt(x) != @as(c_int, 1));
+ \\ var b: bool = (@boolToInt(a) != @as(c_int, 0));
+ \\ var c: bool = @ptrToInt(foo) != 0;
+ \\ return foo((@boolToInt(c) != @boolToInt(b)));
+ \\}
+ });
}