zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

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:
Msrc-self-hosted/clang.zig | 1+
Msrc-self-hosted/translate_c.zig | 28++++++++++++++++++++++++----
Msrc/zig_clang.cpp | 5+++++
Msrc/zig_clang.h | 1+
Mtest/run_translated_c.zig | 17+++++++++++++++++
Mtest/translate_c.zig | 17+++++++++++++++++
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))); + \\} + }); }