Commit cd39f6df95

LemonBoy <thatlemon@gmail.com>
2020-01-05 20:02:28
Better _Bool translation
1 parent 6ff70d3
Changed files (5)
src/zig_clang.cpp
@@ -1809,6 +1809,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();
src/zig_clang.h
@@ -931,6 +931,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);
src-self-hosted/clang.zig
@@ -804,6 +804,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;
src-self-hosted/translate_c.zig
@@ -1273,7 +1273,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, ")");
@@ -1339,9 +1339,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);
@@ -1397,6 +1401,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) {
@@ -1726,6 +1734,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));
@@ -3040,6 +3056,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);
 
@@ -3316,7 +3336,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, ")");
@@ -3341,7 +3361,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, ")");
test/translate_c.zig
@@ -2418,4 +2418,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub export fn c() void {}
         \\pub fn foo() void {}
     });
+
+    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)));
+        \\}
+    });
 }