diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index aa7fe335ae..aa6f06db39 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1210,10 +1210,10 @@ fn transImplicitCastExpr( const c = rp.c; const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); + const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); + const src_type = getExprQualType(c, sub_expr); switch (ZigClangImplicitCastExpr_getCastKind(expr)) { .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast => { - const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); - const src_type = getExprQualType(c, sub_expr); return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); }, .LValueToRValue, .NoOp, .FunctionToPointerDecay, .ArrayToPointerDecay => { @@ -1222,6 +1222,47 @@ fn transImplicitCastExpr( .NullToPointer => { return try transCreateNodeNullLiteral(rp.c); }, + .PointerToBoolean => { + // @ptrToInt(val) != 0 + const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); + try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); + ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); + + const op_token = try appendToken(rp.c, .BangEqual, "!="); + const rhs_node = try transCreateNodeInt(rp.c, 0); + 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); + + 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); + }, + .PointerToIntegral => { + // @intCast(dest_type, @ptrToInt(val)) + const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + try cast_node.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); + _ = try appendToken(rp.c, .Comma, ","); + + const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); + try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); + ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); + try cast_node.params.push(&ptr_to_int.base); + cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return maybeSuppressResult(rp, scope, result_used, &cast_node.base); + }, + .IntegralToPointer => { + // @intToPtr(dest_type, val) + const int_to_ptr = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); + try int_to_ptr.params.push(try transQualType(rp, dest_type, ZigClangImplicitCastExpr_getBeginLoc(expr))); + _ = try appendToken(rp.c, .Comma, ","); + + try int_to_ptr.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); + int_to_ptr.rparen_token = try appendToken(rp.c, .RParen, ")"); + return maybeSuppressResult(rp, scope, result_used, &int_to_ptr.base); + }, else => |kind| return revertAndWarn( rp, error.UnsupportedTranslation, @@ -2224,6 +2265,9 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true); return &op_node.base; }, + .Extension => { + return transExpr(rp, scope, ZigClangUnaryOperator_getSubExpr(stmt), used, .l_value); + }, else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "unsupported C translation {}", .{ZigClangUnaryOperator_getOpcode(stmt)}), } } diff --git a/test/translate_c.zig b/test/translate_c.zig index 517a190756..9bafe90d2a 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -819,6 +819,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.addC("__extension__ cast", + \\int foo(void) { + \\ return __extension__ 1; + \\} + , &[_][]const u8{ + \\pub export fn foo() c_int { + \\ return 1; + \\} + }); + /////////////// Cases that pass for only stage2 //////////////// cases.add_2("Parameterless function prototypes", @@ -2031,43 +2041,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// - - cases.add("macro defines string literal with hex", - \\#define FOO "aoeu\xab derp" - \\#define FOO2 "aoeu\x0007a derp" - \\#define FOO_CHAR '\xfF' - , &[_][]const u8{ - \\pub const FOO = "aoeu\xab derp"; - , - \\pub const FOO2 = "aoeuz derp"; - , - \\pub const FOO_CHAR = 255; - }); - - cases.add("macro defines string literal with octal", - \\#define FOO "aoeu\023 derp" - \\#define FOO2 "aoeu\0234 derp" - \\#define FOO_CHAR '\077' - , &[_][]const u8{ - \\pub const FOO = "aoeu\x13 derp"; - , - \\pub const FOO2 = "aoeu\x134 derp"; - , - \\pub const FOO_CHAR = 63; - }); - - cases.addC("__extension__ cast", - \\int foo(void) { - \\ return __extension__ 1; - \\} - , &[_][]const u8{ - \\pub export fn foo() c_int { - \\ return 1; - \\} - }); - - cases.addC("implicit casts", + cases.add_2("implicit casts", \\#include \\ \\void fn_int(int x); @@ -2103,25 +2077,51 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn fn_bool(x: bool) void; \\pub extern fn fn_ptr(x: ?*c_void) void; \\pub export fn call(q: c_int) void { - \\ fn_int(@floatToInt(c_int, 3.000000)); - \\ fn_int(@floatToInt(c_int, 3.000000)); - \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3)); + \\ fn_int(@floatToInt(c_int, 3)); + \\ fn_int(@floatToInt(c_int, 3)); \\ fn_int(1094861636); \\ fn_f32(@intToFloat(f32, 3)); \\ fn_f64(@intToFloat(f64, 3)); \\ fn_char(@as(u8, '3')); \\ fn_char(@as(u8, '\x01')); \\ fn_char(@as(u8, 0)); - \\ fn_f32(3.000000); - \\ fn_f64(3.000000); - \\ fn_bool(true); - \\ fn_bool(false); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_bool(123 != 0); + \\ fn_bool(0 != 0); \\ fn_bool(@ptrToInt(&fn_int) != 0); \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); \\ fn_ptr(@intToPtr(?*c_void, 42)); \\} }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// + + cases.add("macro defines string literal with hex", + \\#define FOO "aoeu\xab derp" + \\#define FOO2 "aoeu\x0007a derp" + \\#define FOO_CHAR '\xfF' + , &[_][]const u8{ + \\pub const FOO = "aoeu\xab derp"; + , + \\pub const FOO2 = "aoeuz derp"; + , + \\pub const FOO_CHAR = 255; + }); + + cases.add("macro defines string literal with octal", + \\#define FOO "aoeu\023 derp" + \\#define FOO2 "aoeu\0234 derp" + \\#define FOO_CHAR '\077' + , &[_][]const u8{ + \\pub const FOO = "aoeu\x13 derp"; + , + \\pub const FOO2 = "aoeu\x134 derp"; + , + \\pub const FOO_CHAR = 63; + }); + if (builtin.os != builtin.Os.windows) { // sysv_abi not currently supported on windows cases.add("Macro qualified functions", @@ -2990,4 +2990,59 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ }); \\} }); + + cases.addC("implicit casts", + \\#include + \\ + \\void fn_int(int x); + \\void fn_f32(float x); + \\void fn_f64(double x); + \\void fn_char(char x); + \\void fn_bool(bool x); + \\void fn_ptr(void *x); + \\ + \\void call(int q) { + \\ fn_int(3.0f); + \\ fn_int(3.0); + \\ fn_int(3.0L); + \\ fn_int('ABCD'); + \\ fn_f32(3); + \\ fn_f64(3); + \\ fn_char('3'); + \\ fn_char('\x1'); + \\ fn_char(0); + \\ fn_f32(3.0f); + \\ fn_f64(3.0); + \\ fn_bool(123); + \\ fn_bool(0); + \\ fn_bool(&fn_int); + \\ fn_int(&fn_int); + \\ fn_ptr(42); + \\} + , &[_][]const u8{ + \\pub extern fn fn_int(x: c_int) void; + \\pub extern fn fn_f32(x: f32) void; + \\pub extern fn fn_f64(x: f64) void; + \\pub extern fn fn_char(x: u8) void; + \\pub extern fn fn_bool(x: bool) void; + \\pub extern fn fn_ptr(x: ?*c_void) void; + \\pub export fn call(q: c_int) void { + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(@floatToInt(c_int, 3.000000)); + \\ fn_int(1094861636); + \\ fn_f32(@intToFloat(f32, 3)); + \\ fn_f64(@intToFloat(f64, 3)); + \\ fn_char(@as(u8, '3')); + \\ fn_char(@as(u8, '\x01')); + \\ fn_char(@as(u8, 0)); + \\ fn_f32(3.000000); + \\ fn_f64(3.000000); + \\ fn_bool(true); + \\ fn_bool(false); + \\ fn_bool(@ptrToInt(&fn_int) != 0); + \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int))); + \\ fn_ptr(@intToPtr(?*c_void, 42)); + \\} + }); }