authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-01 18:10:43-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-01 18:10:43-05:00
logdc28526c6cd9320fefeebe15a90dd9269cf2b2ca
treeb44dded33d9e911e4de4024a9c9ea75378416c66
parent5575e2a168c07d2dcc0e58146231e490ef8a898e
signaturelock-open Commit is signed but in an unrecognized format.

translate-c: improve support of integer casting

Widening and truncating integer casting to different signedness works better now. For example `(unsigned long)-1` is now translated to zig code that compiles correctly.

3 files changed, 317 insertions(+), 151 deletions(-)

src-self-hosted/clang.zig+2-2
......@@ -804,8 +804,8 @@ pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *cons
804804pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
805805pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
806806pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
807pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass;
808pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType;
807pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;
808pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;
809809pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
810810pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr;
811811pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;
src-self-hosted/translate_c.zig+178-24
......@@ -9,6 +9,7 @@ usingnamespace @import("clang.zig");
99const ctok = @import("c_tokenizer.zig");
1010const CToken = ctok.CToken;
1111const mem = std.mem;
12const math = std.math;
1213
1314const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1415
......@@ -498,10 +499,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
498499 var eq_tok: ast.TokenIndex = undefined;
499500 var init_node: ?*ast.Node = null;
500501
502 // If the initialization expression is not present, initialize with undefined.
503 // If it is an integer literal, we can skip the @as since it will be redundant
504 // with the variable type.
501505 if (ZigClangVarDecl_hasInit(var_decl)) {
502506 eq_tok = try appendToken(c, .Equal, "=");
503507 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
504 transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
508 transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
505509 error.UnsupportedTranslation,
506510 error.UnsupportedType,
507511 => {
......@@ -857,7 +861,7 @@ fn transStmt(
857861 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),
858862 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),
859863 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used),
860 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used),
864 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used, .with_as),
861865 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),
862866 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
863867 .ParenExprClass => {
......@@ -891,7 +895,7 @@ fn transStmt(
891895 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
892896 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
893897 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),
894 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used),
898 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used, .with_as),
895899 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),
896900 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),
897901 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
......@@ -1160,7 +1164,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
11601164
11611165 node.eq_token = try appendToken(c, .Equal, "=");
11621166 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
1163 try transExpr(rp, scope, expr, .used, .r_value)
1167 try transExprCoercing(rp, scope, expr, .used, .r_value)
11641168 else
11651169 try transCreateNodeUndefinedLiteral(c);
11661170 if (isBoolRes(init_node)) {
......@@ -1391,19 +1395,50 @@ fn finishBoolExpr(
13911395 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
13921396}
13931397
1398const SuppressCast = enum {
1399 with_as,
1400 no_as,
1401};
13941402fn transIntegerLiteral(
13951403 rp: RestorePoint,
13961404 scope: *Scope,
13971405 expr: *const ZigClangIntegerLiteral,
13981406 result_used: ResultUsed,
1407 suppress_as: SuppressCast,
13991408) TransError!*ast.Node {
14001409 var eval_result: ZigClangExprEvalResult = undefined;
14011410 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
14021411 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
14031412 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
14041413 }
1405 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1406 return maybeSuppressResult(rp, scope, result_used, node);
1414
1415 if (suppress_as == .no_as) {
1416 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1417 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
1418 }
1419
1420 // Integer literals in C have types, and this can matter for several reasons.
1421 // For example, this is valid C:
1422 // unsigned char y = 256;
1423 // How this gets evaluated is the 256 is an integer, which gets truncated to signed char, then bit-casted
1424 // to unsigned char, resulting in 0. In order for this to work, we have to emit this zig code:
1425 // var y = @bitCast(u8, @truncate(i8, @as(c_int, 256)));
1426 // Ideally in translate-c we could flatten this out to simply:
1427 // var y: u8 = 0;
1428 // But the first step is to be correct, and the next step is to make the output more elegant.
1429
1430 // @as(T, x)
1431 const expr_base = @ptrCast(*const ZigClangExpr, expr);
1432 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1433 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
1434 try as_node.params.push(ty_node);
1435 _ = try appendToken(rp.c, .Comma, ",");
1436
1437 const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
1438 try as_node.params.push(int_lit_node);
1439
1440 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1441 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
14071442}
14081443
14091444fn transReturnStmt(
......@@ -1413,7 +1448,7 @@ fn transReturnStmt(
14131448) TransError!*ast.Node {
14141449 const node = try transCreateNodeReturnExpr(rp.c);
14151450 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
1416 node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
1451 node.rhs = try transExprCoercing(rp, scope, val_expr, .used, .r_value);
14171452 }
14181453 _ = try appendToken(rp.c, .Semicolon, ";");
14191454 return &node.base;
......@@ -1502,11 +1537,41 @@ fn transCCast(
15021537 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
15031538 return transCPtrCast(rp, loc, dst_type, src_type, expr);
15041539 if (cIsInteger(dst_type) and cIsInteger(src_type)) {
1505 // @intCast(dest_type, val)
1506 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
1540 // 1. Extend or truncate without changing signed-ness.
1541 // 2. Bit-cast to correct signed-ness
1542
1543 // @bitCast(dest_type, intermediate_value)
1544 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
15071545 try cast_node.params.push(try transQualType(rp, dst_type, loc));
15081546 _ = try appendToken(rp.c, .Comma, ",");
1509 try cast_node.params.push(expr);
1547
1548 switch (cIntTypeCmp(dst_type, src_type)) {
1549 .lt => {
1550 // @truncate(SameSignSmallerInt, src_type)
1551 const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate");
1552 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
1553 try trunc_node.params.push(ty_node);
1554 _ = try appendToken(rp.c, .Comma, ",");
1555 try trunc_node.params.push(expr);
1556 trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1557
1558 try cast_node.params.push(&trunc_node.base);
1559 },
1560 .gt => {
1561 // @as(SameSignBiggerInt, src_type)
1562 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1563 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
1564 try as_node.params.push(ty_node);
1565 _ = try appendToken(rp.c, .Comma, ",");
1566 try as_node.params.push(expr);
1567 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1568
1569 try cast_node.params.push(&as_node.base);
1570 },
1571 .eq => {
1572 try cast_node.params.push(expr);
1573 },
1574 }
15101575 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
15111576 return &cast_node.base;
15121577 }
......@@ -1579,9 +1644,6 @@ fn transCCast(
15791644 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
15801645 return &builtin_node.base;
15811646 }
1582 // TODO: maybe widen to increase size
1583 // TODO: maybe bitcast to change sign
1584 // TODO: maybe truncate to reduce size
15851647 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
15861648 try cast_node.params.push(try transQualType(rp, dst_type, loc));
15871649 _ = try appendToken(rp.c, .Comma, ",");
......@@ -1600,6 +1662,33 @@ fn transExpr(
16001662 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);
16011663}
16021664
1665/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
1666/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
1667fn transExprCoercing(
1668 rp: RestorePoint,
1669 scope: *Scope,
1670 expr: *const ZigClangExpr,
1671 used: ResultUsed,
1672 lrvalue: LRValue,
1673) TransError!*ast.Node {
1674 switch (ZigClangStmt_getStmtClass(@ptrCast(*const ZigClangStmt, expr))) {
1675 .IntegerLiteralClass => {
1676 return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, expr), .used, .no_as);
1677 },
1678 .CharacterLiteralClass => {
1679 return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, expr), .used, .no_as);
1680 },
1681 .UnaryOperatorClass => {
1682 const un_expr = @ptrCast(*const ZigClangUnaryOperator, expr);
1683 if (ZigClangUnaryOperator_getOpcode(un_expr) == .Extension) {
1684 return transExprCoercing(rp, scope, ZigClangUnaryOperator_getSubExpr(un_expr), used, lrvalue);
1685 }
1686 },
1687 else => {},
1688 }
1689 return transExpr(rp, scope, expr, .used, .r_value);
1690}
1691
16031692fn transInitListExpr(
16041693 rp: RestorePoint,
16051694 scope: *Scope,
......@@ -1625,7 +1714,7 @@ fn transInitListExpr(
16251714 const init_count = ZigClangInitListExpr_getNumInits(expr);
16261715 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
16271716 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
1628 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
1717 const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
16291718 const leftover_count = all_count - init_count;
16301719
16311720 var init_node: *ast.Node.SuffixOp = undefined;
......@@ -2033,16 +2122,17 @@ fn transCharLiteral(
20332122 scope: *Scope,
20342123 stmt: *const ZigClangCharacterLiteral,
20352124 result_used: ResultUsed,
2125 suppress_as: SuppressCast,
20362126) TransError!*ast.Node {
20372127 const kind = ZigClangCharacterLiteral_getKind(stmt);
2038 switch (kind) {
2039 .Ascii, .UTF8 => {
2128 const int_lit_node = switch (kind) {
2129 .Ascii, .UTF8 => blk: {
20402130 const val = ZigClangCharacterLiteral_getValue(stmt);
20412131 if (kind == .Ascii) {
20422132 // C has a somewhat obscure feature called multi-character character
20432133 // constant
20442134 if (val > 255)
2045 return transCreateNodeInt(rp.c, val);
2135 break :blk try transCreateNodeInt(rp.c, val);
20462136 }
20472137 var char_buf: [4]u8 = undefined;
20482138 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
......@@ -2050,7 +2140,7 @@ fn transCharLiteral(
20502140 node.* = .{
20512141 .token = token,
20522142 };
2053 return maybeSuppressResult(rp, scope, result_used, &node.base);
2143 break :blk &node.base;
20542144 },
20552145 .UTF16, .UTF32, .Wide => return revertAndWarn(
20562146 rp,
......@@ -2060,7 +2150,22 @@ fn transCharLiteral(
20602150 .{kind},
20612151 ),
20622152 else => unreachable,
2153 };
2154 if (suppress_as == .no_as) {
2155 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
20632156 }
2157 // See comment in `transIntegerLiteral` for why this code is here.
2158 // @as(T, x)
2159 const expr_base = @ptrCast(*const ZigClangExpr, stmt);
2160 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
2161 const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
2162 try as_node.params.push(ty_node);
2163 _ = try appendToken(rp.c, .Comma, ",");
2164
2165 try as_node.params.push(int_lit_node);
2166
2167 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2168 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
20642169}
20652170
20662171fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node {
......@@ -2480,7 +2585,10 @@ fn transCreateCompoundAssign(
24802585 // zig: lhs += rhs
24812586 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
24822587 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
2483 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2588 var rhs_node = if (is_shift)
2589 try transExprCoercing(rp, scope, rhs, .used, .r_value)
2590 else
2591 try transExpr(rp, scope, rhs, .used, .r_value);
24842592
24852593 if (is_shift) {
24862594 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
......@@ -2681,6 +2789,30 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou
26812789 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
26822790}
26832791
2792/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
2793/// Asserts the type is an integer.
2794fn transQualTypeIntWidthOf(c: *Context, ty: ZigClangQualType, is_signed: bool) TypeError!*ast.Node {
2795 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
2796}
2797
2798/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
2799/// Asserts the type is an integer.
2800fn transTypeIntWidthOf(c: *Context, ty: *const ZigClangType, is_signed: bool) TypeError!*ast.Node {
2801 assert(ZigClangType_getTypeClass(ty) == .Builtin);
2802 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
2803 return transCreateNodeIdentifier(c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2804 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",
2805 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",
2806 .UInt, .Int => if (is_signed) "c_int" else "c_uint",
2807 .ULong, .Long => if (is_signed) "c_long" else "c_ulong",
2808 .ULongLong, .LongLong => if (is_signed) "c_longlong" else "c_ulonglong",
2809 .UInt128, .Int128 => if (is_signed) "i128" else "u128",
2810 .Char16 => if (is_signed) "i16" else "u16",
2811 .Char32 => if (is_signed) "i32" else "u32",
2812 else => unreachable, // only call this function when it has already been determined the type is int
2813 });
2814}
2815
26842816fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
26852817 const c_type = qualTypeCanon(qt);
26862818 if (ZigClangType_getTypeClass(c_type) != .Builtin)
......@@ -2742,7 +2874,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
27422874
27432875 if (int_bit_width != 0) {
27442876 // we can perform the log2 now.
2745 const cast_bit_width = std.math.log2_int(u64, int_bit_width);
2877 const cast_bit_width = math.log2_int(u64, int_bit_width);
27462878 const node = try rp.c.a().create(ast.Node.IntegerLiteral);
27472879 node.* = ast.Node.IntegerLiteral{
27482880 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
......@@ -2902,6 +3034,28 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
29023034 };
29033035}
29043036
3037fn cIntTypeToIndex(qt: ZigClangQualType) u8 {
3038 const c_type = qualTypeCanon(qt);
3039 assert(ZigClangType_getTypeClass(c_type) == .Builtin);
3040 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
3041 return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
3042 .Bool, .Char_U, .Char_S, .UChar, .SChar, .Char8 => 1,
3043 .WChar_U, .WChar_S => 2,
3044 .UShort, .Short, .Char16 => 3,
3045 .UInt, .Int, .Char32 => 4,
3046 .ULong, .Long => 5,
3047 .ULongLong, .LongLong => 6,
3048 .UInt128, .Int128 => 7,
3049 else => unreachable,
3050 };
3051}
3052
3053fn cIntTypeCmp(a: ZigClangQualType, b: ZigClangQualType) math.Order {
3054 const a_index = cIntTypeToIndex(a);
3055 const b_index = cIntTypeToIndex(b);
3056 return math.order(a_index, b_index);
3057}
3058
29053059fn cIsSignedInteger(qt: ZigClangQualType) bool {
29063060 const c_type = qualTypeCanon(qt);
29073061 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
......@@ -2946,7 +3100,7 @@ fn transCreateNodeAssign(
29463100 if (result_used == .unused) {
29473101 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
29483102 const eq_token = try appendToken(rp.c, .Equal, "=");
2949 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
3103 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
29503104 if (isBoolRes(rhs_node)) {
29513105 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
29523106 try builtin_node.params.push(rhs_node);
......@@ -3158,7 +3312,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
31583312 const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
31593313 if (is_negative)
31603314 aps_int = ZigClangAPSInt_negate(aps_int);
3161 var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);
3315 var big = try math.big.Int.initCapacity(c.a(), num_limbs);
31623316 if (is_negative)
31633317 big.negate();
31643318 defer big.deinit();
......@@ -3522,7 +3676,7 @@ fn transCreateNodeShiftOp(
35223676 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
35233677 try as_node.params.push(rhs_type);
35243678 _ = try appendToken(rp.c, .Comma, ",");
3525 const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
3679 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
35263680 try as_node.params.push(rhs);
35273681 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
35283682
......@@ -3652,7 +3806,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
36523806 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, ty);
36533807
36543808 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
3655 const size = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
3809 const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
36563810 var node = try transCreateNodePrefixOp(
36573811 rp.c,
36583812 .{
test/translate_c.zig+137-125
......@@ -17,13 +17,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1717 \\ char b = 123;
1818 \\ const int c;
1919 \\ const unsigned d = 440;
20 \\ int e = 10;
21 \\ unsigned int f = 10u;
2022 \\}
2123 , &[_][]const u8{
2224 \\pub export fn foo() void {
2325 \\ var a: c_int = undefined;
24 \\ var b: u8 = @intCast(u8, 123);
26 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
2527 \\ const c: c_int = undefined;
26 \\ const d: c_uint = @intCast(c_uint, 440);
28 \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440));
29 \\ var e: c_int = 10;
30 \\ var f: c_uint = 10;
2731 \\}
2832 });
2933
......@@ -39,14 +43,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3943 , &[_][]const u8{
4044 \\pub export fn foo() void {
4145 \\ var a: c_int = undefined;
42 \\ _ = 1;
46 \\ _ = @as(c_int, 1);
4347 \\ _ = "hey";
44 \\ _ = (1 + 1);
45 \\ _ = (1 - 1);
48 \\ _ = (@as(c_int, 1) + @as(c_int, 1));
49 \\ _ = (@as(c_int, 1) - @as(c_int, 1));
4650 \\ a = 1;
4751 \\}
4852 });
4953
54 cases.add("function with no prototype",
55 \\int foo() {
56 \\ return 5;
57 \\}
58 , &[_][]const u8{
59 \\pub export fn foo() c_int {
60 \\ return 5;
61 \\}
62 });
63
5064 cases.add("variables",
5165 \\extern int extern_var;
5266 \\static const int int_var = 13;
......@@ -474,26 +488,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
474488 \\}
475489 });
476490
477 cases.add("ignore result, no function arguments",
478 \\void foo() {
479 \\ int a;
480 \\ 1;
481 \\ "hey";
482 \\ 1 + 1;
483 \\ 1 - 1;
484 \\ a = 1;
485 \\}
486 , &[_][]const u8{
487 \\pub export fn foo() void {
488 \\ var a: c_int = undefined;
489 \\ _ = 1;
490 \\ _ = "hey";
491 \\ _ = (1 + 1);
492 \\ _ = (1 - 1);
493 \\ a = 1;
494 \\}
495 });
496
497491 cases.add("constant size array",
498492 \\void func(int array[20]);
499493 , &[_][]const u8{
......@@ -582,7 +576,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
582576 \\pub export fn foo() void {
583577 \\ {
584578 \\ var i: c_int = 0;
585 \\ while (i != 0) : (i = (i + 1)) {}
579 \\ while (i != 0) : (i = (i + @as(c_int, 1))) {}
586580 \\ }
587581 \\}
588582 });
......@@ -721,7 +715,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
721715 \\}
722716 , &[_][]const u8{
723717 \\pub export fn foo() c_int {
724 \\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
718 \\ return (@as(c_int, 1) << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
725719 \\}
726720 });
727721
......@@ -789,7 +783,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
789783 \\ var a: c_int = undefined;
790784 \\ var b: f32 = undefined;
791785 \\ var c: ?*c_void = undefined;
792 \\ return !(a == 0);
786 \\ return !(a == @as(c_int, 0));
793787 \\ return !(a != 0);
794788 \\ return !(b != 0);
795789 \\ return !(c != null);
......@@ -864,7 +858,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
864858 , &[_][]const u8{
865859 \\pub fn foo() void {
866860 \\ var arr: [10]u8 = .{
867 \\ @intCast(u8, 1),
861 \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))),
868862 \\ } ++ .{0} ** 9;
869863 \\ var arr1: [10][*c]u8 = .{
870864 \\ null,
......@@ -1103,18 +1097,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11031097 \\ unsigned d = 440;
11041098 \\}
11051099 , &[_][]const u8{
1106 \\pub var a: c_long = @intCast(c_long, 2);
1107 \\pub var b: c_long = @intCast(c_long, 2);
1100 \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
1101 \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
11081102 \\pub var c: c_int = 4;
11091103 \\pub export fn foo(arg_c_1: u8) void {
11101104 \\ var c_1 = arg_c_1;
11111105 \\ var a_2: c_int = undefined;
1112 \\ var b_3: u8 = @intCast(u8, 123);
1113 \\ b_3 = @intCast(u8, a_2);
1106 \\ var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
1107 \\ b_3 = @bitCast(u8, @truncate(i8, a_2));
11141108 \\ {
11151109 \\ var d: c_int = 5;
11161110 \\ }
1117 \\ var d: c_uint = @intCast(c_uint, 440);
1111 \\ var d: c_uint = @bitCast(c_uint, @as(c_int, 440));
11181112 \\}
11191113 });
11201114
......@@ -1125,11 +1119,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11251119 \\}
11261120 , &[_][]const u8{
11271121 \\pub export fn foo() c_int {
1128 \\ _ = 2;
1129 \\ _ = 4;
1130 \\ _ = 2;
1131 \\ _ = 4;
1132 \\ return 6;
1122 \\ _ = @as(c_int, 2);
1123 \\ _ = @as(c_int, 4);
1124 \\ _ = @as(c_int, 2);
1125 \\ _ = @as(c_int, 4);
1126 \\ return @as(c_int, 6);
11331127 \\}
11341128 });
11351129
......@@ -1144,36 +1138,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11441138 \\ var a: c_int = undefined;
11451139 \\ var b: c_int = undefined;
11461140 \\ a = blk: {
1147 \\ const tmp = 2;
1141 \\ const tmp = @as(c_int, 2);
11481142 \\ b = tmp;
11491143 \\ break :blk tmp;
11501144 \\ };
11511145 \\}
11521146 });
11531147
1154 cases.add("if statements",
1155 \\int foo() {
1156 \\ if (2) {
1157 \\ int a = 2;
1158 \\ }
1159 \\ if (2, 5) {
1160 \\ int a = 2;
1161 \\ }
1162 \\}
1163 , &[_][]const u8{
1164 \\pub export fn foo() c_int {
1165 \\ if (2 != 0) {
1166 \\ var a: c_int = 2;
1167 \\ }
1168 \\ if ((blk: {
1169 \\ _ = 2;
1170 \\ break :blk 5;
1171 \\ }) != 0) {
1172 \\ var a: c_int = 2;
1173 \\ }
1174 \\}
1175 });
1176
11771148 cases.add("while loops",
11781149 \\int foo() {
11791150 \\ int a = 5;
......@@ -1195,21 +1166,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11951166 , &[_][]const u8{
11961167 \\pub export fn foo() c_int {
11971168 \\ var a: c_int = 5;
1198 \\ while (2 != 0) a = 2;
1199 \\ while (4 != 0) {
1169 \\ while (@as(c_int, 2) != 0) a = 2;
1170 \\ while (@as(c_int, 4) != 0) {
12001171 \\ var a_1: c_int = 4;
12011172 \\ a_1 = 9;
1202 \\ _ = 6;
1173 \\ _ = @as(c_int, 6);
12031174 \\ return a_1;
12041175 \\ }
12051176 \\ while (true) {
12061177 \\ var a_1: c_int = 2;
12071178 \\ a_1 = 12;
1208 \\ if (!(4 != 0)) break;
1179 \\ if (!(@as(c_int, 4) != 0)) break;
12091180 \\ }
12101181 \\ while (true) {
12111182 \\ a = 7;
1212 \\ if (!(4 != 0)) break;
1183 \\ if (!(@as(c_int, 4) != 0)) break;
12131184 \\ }
12141185 \\}
12151186 });
......@@ -1227,21 +1198,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12271198 \\ {
12281199 \\ var i: c_int = 2;
12291200 \\ var b: c_int = 4;
1230 \\ while ((i + 2) != 0) : (i = 2) {
1201 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
12311202 \\ var a: c_int = 2;
12321203 \\ a = 6;
1233 \\ _ = 5;
1234 \\ _ = 7;
1204 \\ _ = @as(c_int, 5);
1205 \\ _ = @as(c_int, 7);
12351206 \\ }
12361207 \\ }
1237 \\ var i: u8 = @intCast(u8, 2);
1208 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
12381209 \\}
12391210 });
12401211
12411212 cases.add("shadowing primitive types",
12421213 \\unsigned anyerror = 2;
12431214 , &[_][]const u8{
1244 \\pub export var _anyerror: c_uint = @intCast(c_uint, 2);
1215 \\pub export var _anyerror: c_uint = @bitCast(c_uint, @as(c_int, 2));
12451216 });
12461217
12471218 cases.add("floats",
......@@ -1253,7 +1224,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12531224 \\pub export var a: f32 = @floatCast(f32, 3.1415);
12541225 \\pub export var b: f64 = 3.1415;
12551226 \\pub export var c: c_int = @floatToInt(c_int, 3.1415);
1256 \\pub export var d: f64 = @intToFloat(f64, 3);
1227 \\pub export var d: f64 = @intToFloat(f64, @as(c_int, 3));
12571228 });
12581229
12591230 cases.add("conditional operator",
......@@ -1263,8 +1234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
12631234 \\}
12641235 , &[_][]const u8{
12651236 \\pub export fn bar() c_int {
1266 \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2;
1267 \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6;
1237 \\ if ((if (@as(c_int, 2) != 0) @as(c_int, 5) else (if (@as(c_int, 5) != 0) @as(c_int, 4) else @as(c_int, 6))) != 0) _ = @as(c_int, 2);
1238 \\ return if (@as(c_int, 2) != 0) @as(c_int, 5) else if (@as(c_int, 5) != 0) @as(c_int, 4) else @as(c_int, 6);
12681239 \\}
12691240 });
12701241
......@@ -1303,7 +1274,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13031274 \\ }
13041275 \\ res = 2;
13051276 \\ }
1306 \\ res = (3 * i);
1277 \\ res = (@as(c_int, 3) * i);
13071278 \\ break :__switch;
13081279 \\ }
13091280 \\ res = 5;
......@@ -1397,6 +1368,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13971368 \\}
13981369 });
13991370
1371 // TODO translate-c should in theory be able to figure out to drop all these casts
14001372 cases.add("escape sequences",
14011373 \\const char *escapes() {
14021374 \\char a = '\'',
......@@ -1415,17 +1387,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14151387 \\
14161388 , &[_][]const u8{
14171389 \\pub export fn escapes() [*c]const u8 {
1418 \\ var a: u8 = @intCast(u8, '\'');
1419 \\ var b: u8 = @intCast(u8, '\\');
1420 \\ var c: u8 = @intCast(u8, '\x07');
1421 \\ var d: u8 = @intCast(u8, '\x08');
1422 \\ var e: u8 = @intCast(u8, '\x0c');
1423 \\ var f: u8 = @intCast(u8, '\n');
1424 \\ var g: u8 = @intCast(u8, '\r');
1425 \\ var h: u8 = @intCast(u8, '\t');
1426 \\ var i: u8 = @intCast(u8, '\x0b');
1427 \\ var j: u8 = @intCast(u8, '\x00');
1428 \\ var k: u8 = @intCast(u8, '\"');
1390 \\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));
1391 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));
1392 \\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));
1393 \\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));
1394 \\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));
1395 \\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));
1396 \\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));
1397 \\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));
1398 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));
1399 \\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));
1400 \\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));
14291401 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
14301402 \\}
14311403 });
......@@ -1446,12 +1418,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14461418 \\pub export fn foo() void {
14471419 \\ var a: c_int = 2;
14481420 \\ while (true) {
1449 \\ a = (a - 1);
1421 \\ a = (a - @as(c_int, 1));
14501422 \\ if (!(a != 0)) break;
14511423 \\ }
14521424 \\ var b: c_int = 2;
14531425 \\ while (true) {
1454 \\ b = (b - 1);
1426 \\ b = (b - @as(c_int, 1));
14551427 \\ if (!(b != 0)) break;
14561428 \\ }
14571429 \\}
......@@ -1602,7 +1574,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16021574 \\pub const yes = [*c]u8;
16031575 \\pub export fn foo() void {
16041576 \\ var a: yes = undefined;
1605 \\ if (a != null) _ = 2;
1577 \\ if (a != null) _ = @as(c_int, 2);
16061578 \\}
16071579 });
16081580
......@@ -1695,7 +1667,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16951667 \\}
16961668 });
16971669
1698 cases.add("if statement",
1670 cases.add("simple if statement",
16991671 \\int max(int a, int b) {
17001672 \\ if (a < b)
17011673 \\ return b;
......@@ -1717,6 +1689,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17171689 \\}
17181690 });
17191691
1692 cases.add("if statements",
1693 \\int foo() {
1694 \\ if (2) {
1695 \\ int a = 2;
1696 \\ }
1697 \\ if (2, 5) {
1698 \\ int a = 2;
1699 \\ }
1700 \\}
1701 , &[_][]const u8{
1702 \\pub export fn foo() c_int {
1703 \\ if (@as(c_int, 2) != 0) {
1704 \\ var a: c_int = 2;
1705 \\ }
1706 \\ if ((blk: {
1707 \\ _ = @as(c_int, 2);
1708 \\ break :blk @as(c_int, 5);
1709 \\ }) != 0) {
1710 \\ var a: c_int = 2;
1711 \\ }
1712 \\}
1713 });
1714
17201715 cases.add("if on non-bool",
17211716 \\enum SomeEnum { A, B, C };
17221717 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
......@@ -1764,7 +1759,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17641759 , &[_][]const u8{
17651760 \\pub export fn abs(arg_a: c_int) c_int {
17661761 \\ var a = arg_a;
1767 \\ return if (a < 0) -a else a;
1762 \\ return if (a < @as(c_int, 0)) -a else a;
17681763 \\}
17691764 });
17701765
......@@ -1845,7 +1840,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18451840 , &[_][]const u8{
18461841 \\pub export fn foo() void {
18471842 \\ var i: c_int = 0;
1848 \\ var u: c_uint = @intCast(c_uint, 0);
1843 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
18491844 \\ i += 1;
18501845 \\ i -= 1;
18511846 \\ u +%= 1;
......@@ -1885,7 +1880,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18851880 \\pub export fn log2(arg_a: c_uint) c_int {
18861881 \\ var a = arg_a;
18871882 \\ var i: c_int = 0;
1888 \\ while (a > @intCast(c_uint, 0)) {
1883 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
18891884 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
18901885 \\ }
18911886 \\ return i;
......@@ -1905,7 +1900,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19051900 \\pub export fn log2(arg_a: u32) c_int {
19061901 \\ var a = arg_a;
19071902 \\ var i: c_int = 0;
1908 \\ while (a > @intCast(c_uint, 0)) {
1903 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
19091904 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
19101905 \\ }
19111906 \\ return i;
......@@ -1929,42 +1924,42 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19291924 \\ var a: c_int = 0;
19301925 \\ a += (blk: {
19311926 \\ const ref = &a;
1932 \\ ref.* = ref.* + 1;
1927 \\ ref.* = ref.* + @as(c_int, 1);
19331928 \\ break :blk ref.*;
19341929 \\ });
19351930 \\ a -= (blk: {
19361931 \\ const ref = &a;
1937 \\ ref.* = ref.* - 1;
1932 \\ ref.* = ref.* - @as(c_int, 1);
19381933 \\ break :blk ref.*;
19391934 \\ });
19401935 \\ a *= (blk: {
19411936 \\ const ref = &a;
1942 \\ ref.* = ref.* * 1;
1937 \\ ref.* = ref.* * @as(c_int, 1);
19431938 \\ break :blk ref.*;
19441939 \\ });
19451940 \\ a &= (blk: {
19461941 \\ const ref = &a;
1947 \\ ref.* = ref.* & 1;
1942 \\ ref.* = ref.* & @as(c_int, 1);
19481943 \\ break :blk ref.*;
19491944 \\ });
19501945 \\ a |= (blk: {
19511946 \\ const ref = &a;
1952 \\ ref.* = ref.* | 1;
1947 \\ ref.* = ref.* | @as(c_int, 1);
19531948 \\ break :blk ref.*;
19541949 \\ });
19551950 \\ a ^= (blk: {
19561951 \\ const ref = &a;
1957 \\ ref.* = ref.* ^ 1;
1952 \\ ref.* = ref.* ^ @as(c_int, 1);
19581953 \\ break :blk ref.*;
19591954 \\ });
19601955 \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
19611956 \\ const ref = &a;
1962 \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), 1);
1957 \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
19631958 \\ break :blk ref.*;
19641959 \\ }));
19651960 \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
19661961 \\ const ref = &a;
1967 \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), 1);
1962 \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
19681963 \\ break :blk ref.*;
19691964 \\ }));
19701965 \\}
......@@ -1984,45 +1979,45 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19841979 \\}
19851980 , &[_][]const u8{
19861981 \\pub export fn foo() void {
1987 \\ var a: c_uint = @intCast(c_uint, 0);
1982 \\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0));
19881983 \\ a +%= (blk: {
19891984 \\ const ref = &a;
1990 \\ ref.* = ref.* +% @intCast(c_uint, 1);
1985 \\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));
19911986 \\ break :blk ref.*;
19921987 \\ });
19931988 \\ a -%= (blk: {
19941989 \\ const ref = &a;
1995 \\ ref.* = ref.* -% @intCast(c_uint, 1);
1990 \\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));
19961991 \\ break :blk ref.*;
19971992 \\ });
19981993 \\ a *%= (blk: {
19991994 \\ const ref = &a;
2000 \\ ref.* = ref.* *% @intCast(c_uint, 1);
1995 \\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));
20011996 \\ break :blk ref.*;
20021997 \\ });
20031998 \\ a &= (blk: {
20041999 \\ const ref = &a;
2005 \\ ref.* = ref.* & @intCast(c_uint, 1);
2000 \\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));
20062001 \\ break :blk ref.*;
20072002 \\ });
20082003 \\ a |= (blk: {
20092004 \\ const ref = &a;
2010 \\ ref.* = ref.* | @intCast(c_uint, 1);
2005 \\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));
20112006 \\ break :blk ref.*;
20122007 \\ });
20132008 \\ a ^= (blk: {
20142009 \\ const ref = &a;
2015 \\ ref.* = ref.* ^ @intCast(c_uint, 1);
2010 \\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));
20162011 \\ break :blk ref.*;
20172012 \\ });
20182013 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
20192014 \\ const ref = &a;
2020 \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), 1);
2015 \\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
20212016 \\ break :blk ref.*;
20222017 \\ }));
20232018 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
20242019 \\ const ref = &a;
2025 \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), 1);
2020 \\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
20262021 \\ break :blk ref.*;
20272022 \\ }));
20282023 \\}
......@@ -2044,7 +2039,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20442039 , &[_][]const u8{
20452040 \\pub export fn foo() void {
20462041 \\ var i: c_int = 0;
2047 \\ var u: c_uint = @intCast(c_uint, 0);
2042 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
20482043 \\ i += 1;
20492044 \\ i -= 1;
20502045 \\ u +%= 1;
......@@ -2115,19 +2110,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21152110 \\ fn_int(@floatToInt(c_int, 3));
21162111 \\ fn_int(@floatToInt(c_int, 3));
21172112 \\ fn_int(@floatToInt(c_int, 3));
2118 \\ fn_int(1094861636);
2119 \\ fn_f32(@intToFloat(f32, 3));
2120 \\ fn_f64(@intToFloat(f64, 3));
2121 \\ fn_char(@intCast(u8, '3'));
2122 \\ fn_char(@intCast(u8, '\x01'));
2123 \\ fn_char(@intCast(u8, 0));
2113 \\ fn_int(@as(c_int, 1094861636));
2114 \\ fn_f32(@intToFloat(f32, @as(c_int, 3)));
2115 \\ fn_f64(@intToFloat(f64, @as(c_int, 3)));
2116 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3'))));
2117 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01'))));
2118 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0))));
21242119 \\ fn_f32(3);
21252120 \\ fn_f64(3);
2126 \\ fn_bool(123 != 0);
2127 \\ fn_bool(0 != 0);
2121 \\ fn_bool(@as(c_int, 123) != 0);
2122 \\ fn_bool(@as(c_int, 0) != 0);
21282123 \\ fn_bool(@ptrToInt(&fn_int) != 0);
21292124 \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int)));
2130 \\ fn_ptr(@intToPtr(?*c_void, 42));
2125 \\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42)));
21312126 \\}
21322127 });
21332128
......@@ -2223,8 +2218,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22232218 \\}
22242219 , &[_][]const u8{
22252220 \\pub fn foo() void {
2226 \\ if (1 != 0) while (true) {
2227 \\ if (!(0 != 0)) break;
2221 \\ if (@as(c_int, 1) != 0) while (true) {
2222 \\ if (!(@as(c_int, 0) != 0)) break;
22282223 \\ };
22292224 \\}
22302225 });
......@@ -2263,4 +2258,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22632258 \\ };
22642259 \\}
22652260 });
2261
2262 cases.add("widening and truncating integer casting to different signedness",
2263 \\unsigned long foo(void) {
2264 \\ return -1;
2265 \\}
2266 \\unsigned short bar(long x) {
2267 \\ return x;
2268 \\}
2269 , &[_][]const u8{
2270 \\pub export fn foo() c_ulong {
2271 \\ return @bitCast(c_ulong, @as(c_long, -@as(c_int, 1)));
2272 \\}
2273 \\pub export fn bar(arg_x: c_long) c_ushort {
2274 \\ var x = arg_x;
2275 \\ return @bitCast(c_ushort, @truncate(c_short, x));
2276 \\}
2277 });
22662278}