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
signature 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...@@ -804,8 +804,8 @@ pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *cons
804pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;804pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
805pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;805pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
806pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;806pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
807pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass;807pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;
808pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType;808pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;
809pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;809pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
810pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr;810pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr;
811pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;811pub 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");...@@ -9,6 +9,7 @@ usingnamespace @import("clang.zig");
9const ctok = @import("c_tokenizer.zig");9const ctok = @import("c_tokenizer.zig");
10const CToken = ctok.CToken;10const CToken = ctok.CToken;
11const mem = std.mem;11const mem = std.mem;
12const math = std.math;
1213
13const CallingConvention = std.builtin.TypeInfo.CallingConvention;14const CallingConvention = std.builtin.TypeInfo.CallingConvention;
1415
...@@ -498,10 +499,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {...@@ -498,10 +499,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
498 var eq_tok: ast.TokenIndex = undefined;499 var eq_tok: ast.TokenIndex = undefined;
499 var init_node: ?*ast.Node = null;500 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.
501 if (ZigClangVarDecl_hasInit(var_decl)) {505 if (ZigClangVarDecl_hasInit(var_decl)) {
502 eq_tok = try appendToken(c, .Equal, "=");506 eq_tok = try appendToken(c, .Equal, "=");
503 init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|507 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) {
505 error.UnsupportedTranslation,509 error.UnsupportedTranslation,
506 error.UnsupportedType,510 error.UnsupportedType,
507 => {511 => {
...@@ -857,7 +861,7 @@ fn transStmt(...@@ -857,7 +861,7 @@ fn transStmt(
857 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),861 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),
858 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),862 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),
859 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used),863 .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),
861 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),865 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),
862 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),866 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
863 .ParenExprClass => {867 .ParenExprClass => {
...@@ -891,7 +895,7 @@ fn transStmt(...@@ -891,7 +895,7 @@ fn transStmt(
891 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),895 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
892 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),896 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
893 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),897 .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),
895 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),899 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),
896 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),900 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),
897 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),901 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
...@@ -1160,7 +1164,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)...@@ -1160,7 +1164,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
11601164
1161 node.eq_token = try appendToken(c, .Equal, "=");1165 node.eq_token = try appendToken(c, .Equal, "=");
1162 var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|1166 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)
1164 else1168 else
1165 try transCreateNodeUndefinedLiteral(c);1169 try transCreateNodeUndefinedLiteral(c);
1166 if (isBoolRes(init_node)) {1170 if (isBoolRes(init_node)) {
...@@ -1391,19 +1395,50 @@ fn finishBoolExpr(...@@ -1391,19 +1395,50 @@ fn finishBoolExpr(
1391 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});1395 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
1392}1396}
13931397
1398const SuppressCast = enum {
1399 with_as,
1400 no_as,
1401};
1394fn transIntegerLiteral(1402fn transIntegerLiteral(
1395 rp: RestorePoint,1403 rp: RestorePoint,
1396 scope: *Scope,1404 scope: *Scope,
1397 expr: *const ZigClangIntegerLiteral,1405 expr: *const ZigClangIntegerLiteral,
1398 result_used: ResultUsed,1406 result_used: ResultUsed,
1407 suppress_as: SuppressCast,
1399) TransError!*ast.Node {1408) TransError!*ast.Node {
1400 var eval_result: ZigClangExprEvalResult = undefined;1409 var eval_result: ZigClangExprEvalResult = undefined;
1401 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {1410 if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
1402 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);1411 const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
1403 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});1412 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1404 }1413 }
1405 const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));1414
1406 return maybeSuppressResult(rp, scope, result_used, node);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);
1407}1442}
14081443
1409fn transReturnStmt(1444fn transReturnStmt(
...@@ -1413,7 +1448,7 @@ fn transReturnStmt(...@@ -1413,7 +1448,7 @@ fn transReturnStmt(
1413) TransError!*ast.Node {1448) TransError!*ast.Node {
1414 const node = try transCreateNodeReturnExpr(rp.c);1449 const node = try transCreateNodeReturnExpr(rp.c);
1415 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {1450 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);
1417 }1452 }
1418 _ = try appendToken(rp.c, .Semicolon, ";");1453 _ = try appendToken(rp.c, .Semicolon, ";");
1419 return &node.base;1454 return &node.base;
...@@ -1502,11 +1537,41 @@ fn transCCast(...@@ -1502,11 +1537,41 @@ fn transCCast(
1502 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))1537 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
1503 return transCPtrCast(rp, loc, dst_type, src_type, expr);1538 return transCPtrCast(rp, loc, dst_type, src_type, expr);
1504 if (cIsInteger(dst_type) and cIsInteger(src_type)) {1539 if (cIsInteger(dst_type) and cIsInteger(src_type)) {
1505 // @intCast(dest_type, val)1540 // 1. Extend or truncate without changing signed-ness.
1506 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");1541 // 2. Bit-cast to correct signed-ness
1542
1543 // @bitCast(dest_type, intermediate_value)
1544 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
1507 try cast_node.params.push(try transQualType(rp, dst_type, loc));1545 try cast_node.params.push(try transQualType(rp, dst_type, loc));
1508 _ = try appendToken(rp.c, .Comma, ",");1546 _ = 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 }
1510 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1575 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1511 return &cast_node.base;1576 return &cast_node.base;
1512 }1577 }
...@@ -1579,9 +1644,6 @@ fn transCCast(...@@ -1579,9 +1644,6 @@ fn transCCast(
1579 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");1644 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1580 return &builtin_node.base;1645 return &builtin_node.base;
1581 }1646 }
1582 // TODO: maybe widen to increase size
1583 // TODO: maybe bitcast to change sign
1584 // TODO: maybe truncate to reduce size
1585 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");1647 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1586 try cast_node.params.push(try transQualType(rp, dst_type, loc));1648 try cast_node.params.push(try transQualType(rp, dst_type, loc));
1587 _ = try appendToken(rp.c, .Comma, ",");1649 _ = try appendToken(rp.c, .Comma, ",");
...@@ -1600,6 +1662,33 @@ fn transExpr(...@@ -1600,6 +1662,33 @@ fn transExpr(
1600 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);1662 return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);
1601}1663}
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
1603fn transInitListExpr(1692fn transInitListExpr(
1604 rp: RestorePoint,1693 rp: RestorePoint,
1605 scope: *Scope,1694 scope: *Scope,
...@@ -1625,7 +1714,7 @@ fn transInitListExpr(...@@ -1625,7 +1714,7 @@ fn transInitListExpr(
1625 const init_count = ZigClangInitListExpr_getNumInits(expr);1714 const init_count = ZigClangInitListExpr_getNumInits(expr);
1626 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);1715 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
1627 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);1716 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));
1629 const leftover_count = all_count - init_count;1718 const leftover_count = all_count - init_count;
16301719
1631 var init_node: *ast.Node.SuffixOp = undefined;1720 var init_node: *ast.Node.SuffixOp = undefined;
...@@ -2033,16 +2122,17 @@ fn transCharLiteral(...@@ -2033,16 +2122,17 @@ fn transCharLiteral(
2033 scope: *Scope,2122 scope: *Scope,
2034 stmt: *const ZigClangCharacterLiteral,2123 stmt: *const ZigClangCharacterLiteral,
2035 result_used: ResultUsed,2124 result_used: ResultUsed,
2125 suppress_as: SuppressCast,
2036) TransError!*ast.Node {2126) TransError!*ast.Node {
2037 const kind = ZigClangCharacterLiteral_getKind(stmt);2127 const kind = ZigClangCharacterLiteral_getKind(stmt);
2038 switch (kind) {2128 const int_lit_node = switch (kind) {
2039 .Ascii, .UTF8 => {2129 .Ascii, .UTF8 => blk: {
2040 const val = ZigClangCharacterLiteral_getValue(stmt);2130 const val = ZigClangCharacterLiteral_getValue(stmt);
2041 if (kind == .Ascii) {2131 if (kind == .Ascii) {
2042 // C has a somewhat obscure feature called multi-character character2132 // C has a somewhat obscure feature called multi-character character
2043 // constant2133 // constant
2044 if (val > 255)2134 if (val > 255)
2045 return transCreateNodeInt(rp.c, val);2135 break :blk try transCreateNodeInt(rp.c, val);
2046 }2136 }
2047 var char_buf: [4]u8 = undefined;2137 var char_buf: [4]u8 = undefined;
2048 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});2138 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
...@@ -2050,7 +2140,7 @@ fn transCharLiteral(...@@ -2050,7 +2140,7 @@ fn transCharLiteral(
2050 node.* = .{2140 node.* = .{
2051 .token = token,2141 .token = token,
2052 };2142 };
2053 return maybeSuppressResult(rp, scope, result_used, &node.base);2143 break :blk &node.base;
2054 },2144 },
2055 .UTF16, .UTF32, .Wide => return revertAndWarn(2145 .UTF16, .UTF32, .Wide => return revertAndWarn(
2056 rp,2146 rp,
...@@ -2060,7 +2150,22 @@ fn transCharLiteral(...@@ -2060,7 +2150,22 @@ fn transCharLiteral(
2060 .{kind},2150 .{kind},
2061 ),2151 ),
2062 else => unreachable,2152 else => unreachable,
2153 };
2154 if (suppress_as == .no_as) {
2155 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
2063 }2156 }
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);
2064}2169}
20652170
2066fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node {2171fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node {
...@@ -2480,7 +2585,10 @@ fn transCreateCompoundAssign(...@@ -2480,7 +2585,10 @@ fn transCreateCompoundAssign(
2480 // zig: lhs += rhs2585 // zig: lhs += rhs
2481 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2586 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
2482 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);2587 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
2485 if (is_shift) {2593 if (is_shift) {
2486 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");2594 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
...@@ -2681,6 +2789,30 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou...@@ -2681,6 +2789,30 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou
2681 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);2789 return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
2682}2790}
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
2684fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {2816fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
2685 const c_type = qualTypeCanon(qt);2817 const c_type = qualTypeCanon(qt);
2686 if (ZigClangType_getTypeClass(c_type) != .Builtin)2818 if (ZigClangType_getTypeClass(c_type) != .Builtin)
...@@ -2742,7 +2874,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC...@@ -2742,7 +2874,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
27422874
2743 if (int_bit_width != 0) {2875 if (int_bit_width != 0) {
2744 // we can perform the log2 now.2876 // 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);
2746 const node = try rp.c.a().create(ast.Node.IntegerLiteral);2878 const node = try rp.c.a().create(ast.Node.IntegerLiteral);
2747 node.* = ast.Node.IntegerLiteral{2879 node.* = ast.Node.IntegerLiteral{
2748 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),2880 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
...@@ -2902,6 +3034,28 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {...@@ -2902,6 +3034,28 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
2902 };3034 };
2903}3035}
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
2905fn cIsSignedInteger(qt: ZigClangQualType) bool {3059fn cIsSignedInteger(qt: ZigClangQualType) bool {
2906 const c_type = qualTypeCanon(qt);3060 const c_type = qualTypeCanon(qt);
2907 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;3061 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
...@@ -2946,7 +3100,7 @@ fn transCreateNodeAssign(...@@ -2946,7 +3100,7 @@ fn transCreateNodeAssign(
2946 if (result_used == .unused) {3100 if (result_used == .unused) {
2947 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3101 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
2948 const eq_token = try appendToken(rp.c, .Equal, "=");3102 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);
2950 if (isBoolRes(rhs_node)) {3104 if (isBoolRes(rhs_node)) {
2951 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");3105 const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
2952 try builtin_node.params.push(rhs_node);3106 try builtin_node.params.push(rhs_node);
...@@ -3158,7 +3312,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {...@@ -3158,7 +3312,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
3158 const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);3312 const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
3159 if (is_negative)3313 if (is_negative)
3160 aps_int = ZigClangAPSInt_negate(aps_int);3314 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);
3162 if (is_negative)3316 if (is_negative)
3163 big.negate();3317 big.negate();
3164 defer big.deinit();3318 defer big.deinit();
...@@ -3522,7 +3676,7 @@ fn transCreateNodeShiftOp(...@@ -3522,7 +3676,7 @@ fn transCreateNodeShiftOp(
3522 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);3676 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
3523 try as_node.params.push(rhs_type);3677 try as_node.params.push(rhs_type);
3524 _ = try appendToken(rp.c, .Comma, ",");3678 _ = 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);
3526 try as_node.params.push(rhs);3680 try as_node.params.push(rhs);
3527 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");3681 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
35283682
...@@ -3652,7 +3806,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour...@@ -3652,7 +3806,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
3652 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, ty);3806 const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, ty);
36533807
3654 const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);3808 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));
3656 var node = try transCreateNodePrefixOp(3810 var node = try transCreateNodePrefixOp(
3657 rp.c,3811 rp.c,
3658 .{3812 .{
test/translate_c.zig+137-125
...@@ -17,13 +17,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -17,13 +17,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17 \\ char b = 123;17 \\ char b = 123;
18 \\ const int c;18 \\ const int c;
19 \\ const unsigned d = 440;19 \\ const unsigned d = 440;
20 \\ int e = 10;
21 \\ unsigned int f = 10u;
20 \\}22 \\}
21 , &[_][]const u8{23 , &[_][]const u8{
22 \\pub export fn foo() void {24 \\pub export fn foo() void {
23 \\ var a: c_int = undefined;25 \\ var a: c_int = undefined;
24 \\ var b: u8 = @intCast(u8, 123);26 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
25 \\ const c: c_int = undefined;27 \\ 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;
27 \\}31 \\}
28 });32 });
2933
...@@ -39,14 +43,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -39,14 +43,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
39 , &[_][]const u8{43 , &[_][]const u8{
40 \\pub export fn foo() void {44 \\pub export fn foo() void {
41 \\ var a: c_int = undefined;45 \\ var a: c_int = undefined;
42 \\ _ = 1;46 \\ _ = @as(c_int, 1);
43 \\ _ = "hey";47 \\ _ = "hey";
44 \\ _ = (1 + 1);48 \\ _ = (@as(c_int, 1) + @as(c_int, 1));
45 \\ _ = (1 - 1);49 \\ _ = (@as(c_int, 1) - @as(c_int, 1));
46 \\ a = 1;50 \\ a = 1;
47 \\}51 \\}
48 });52 });
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
50 cases.add("variables",64 cases.add("variables",
51 \\extern int extern_var;65 \\extern int extern_var;
52 \\static const int int_var = 13;66 \\static const int int_var = 13;
...@@ -474,26 +488,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -474,26 +488,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
474 \\}488 \\}
475 });489 });
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
497 cases.add("constant size array",491 cases.add("constant size array",
498 \\void func(int array[20]);492 \\void func(int array[20]);
499 , &[_][]const u8{493 , &[_][]const u8{
...@@ -582,7 +576,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -582,7 +576,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
582 \\pub export fn foo() void {576 \\pub export fn foo() void {
583 \\ {577 \\ {
584 \\ var i: c_int = 0;578 \\ var i: c_int = 0;
585 \\ while (i != 0) : (i = (i + 1)) {}579 \\ while (i != 0) : (i = (i + @as(c_int, 1))) {}
586 \\ }580 \\ }
587 \\}581 \\}
588 });582 });
...@@ -721,7 +715,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -721,7 +715,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
721 \\}715 \\}
722 , &[_][]const u8{716 , &[_][]const u8{
723 \\pub export fn foo() c_int {717 \\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);
725 \\}719 \\}
726 });720 });
727721
...@@ -789,7 +783,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -789,7 +783,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
789 \\ var a: c_int = undefined;783 \\ var a: c_int = undefined;
790 \\ var b: f32 = undefined;784 \\ var b: f32 = undefined;
791 \\ var c: ?*c_void = undefined;785 \\ var c: ?*c_void = undefined;
792 \\ return !(a == 0);786 \\ return !(a == @as(c_int, 0));
793 \\ return !(a != 0);787 \\ return !(a != 0);
794 \\ return !(b != 0);788 \\ return !(b != 0);
795 \\ return !(c != null);789 \\ return !(c != null);
...@@ -864,7 +858,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -864,7 +858,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
864 , &[_][]const u8{858 , &[_][]const u8{
865 \\pub fn foo() void {859 \\pub fn foo() void {
866 \\ var arr: [10]u8 = .{860 \\ var arr: [10]u8 = .{
867 \\ @intCast(u8, 1),861 \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))),
868 \\ } ++ .{0} ** 9;862 \\ } ++ .{0} ** 9;
869 \\ var arr1: [10][*c]u8 = .{863 \\ var arr1: [10][*c]u8 = .{
870 \\ null,864 \\ null,
...@@ -1103,18 +1097,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1103,18 +1097,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1103 \\ unsigned d = 440;1097 \\ unsigned d = 440;
1104 \\}1098 \\}
1105 , &[_][]const u8{1099 , &[_][]const u8{
1106 \\pub var a: c_long = @intCast(c_long, 2);1100 \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
1107 \\pub var b: c_long = @intCast(c_long, 2);1101 \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
1108 \\pub var c: c_int = 4;1102 \\pub var c: c_int = 4;
1109 \\pub export fn foo(arg_c_1: u8) void {1103 \\pub export fn foo(arg_c_1: u8) void {
1110 \\ var c_1 = arg_c_1;1104 \\ var c_1 = arg_c_1;
1111 \\ var a_2: c_int = undefined;1105 \\ var a_2: c_int = undefined;
1112 \\ var b_3: u8 = @intCast(u8, 123);1106 \\ var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
1113 \\ b_3 = @intCast(u8, a_2);1107 \\ b_3 = @bitCast(u8, @truncate(i8, a_2));
1114 \\ {1108 \\ {
1115 \\ var d: c_int = 5;1109 \\ var d: c_int = 5;
1116 \\ }1110 \\ }
1117 \\ var d: c_uint = @intCast(c_uint, 440);1111 \\ var d: c_uint = @bitCast(c_uint, @as(c_int, 440));
1118 \\}1112 \\}
1119 });1113 });
11201114
...@@ -1125,11 +1119,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1125,11 +1119,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1125 \\}1119 \\}
1126 , &[_][]const u8{1120 , &[_][]const u8{
1127 \\pub export fn foo() c_int {1121 \\pub export fn foo() c_int {
1128 \\ _ = 2;1122 \\ _ = @as(c_int, 2);
1129 \\ _ = 4;1123 \\ _ = @as(c_int, 4);
1130 \\ _ = 2;1124 \\ _ = @as(c_int, 2);
1131 \\ _ = 4;1125 \\ _ = @as(c_int, 4);
1132 \\ return 6;1126 \\ return @as(c_int, 6);
1133 \\}1127 \\}
1134 });1128 });
11351129
...@@ -1144,36 +1138,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1144,36 +1138,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1144 \\ var a: c_int = undefined;1138 \\ var a: c_int = undefined;
1145 \\ var b: c_int = undefined;1139 \\ var b: c_int = undefined;
1146 \\ a = blk: {1140 \\ a = blk: {
1147 \\ const tmp = 2;1141 \\ const tmp = @as(c_int, 2);
1148 \\ b = tmp;1142 \\ b = tmp;
1149 \\ break :blk tmp;1143 \\ break :blk tmp;
1150 \\ };1144 \\ };
1151 \\}1145 \\}
1152 });1146 });
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
1177 cases.add("while loops",1148 cases.add("while loops",
1178 \\int foo() {1149 \\int foo() {
1179 \\ int a = 5;1150 \\ int a = 5;
...@@ -1195,21 +1166,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1195,21 +1166,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1195 , &[_][]const u8{1166 , &[_][]const u8{
1196 \\pub export fn foo() c_int {1167 \\pub export fn foo() c_int {
1197 \\ var a: c_int = 5;1168 \\ var a: c_int = 5;
1198 \\ while (2 != 0) a = 2;1169 \\ while (@as(c_int, 2) != 0) a = 2;
1199 \\ while (4 != 0) {1170 \\ while (@as(c_int, 4) != 0) {
1200 \\ var a_1: c_int = 4;1171 \\ var a_1: c_int = 4;
1201 \\ a_1 = 9;1172 \\ a_1 = 9;
1202 \\ _ = 6;1173 \\ _ = @as(c_int, 6);
1203 \\ return a_1;1174 \\ return a_1;
1204 \\ }1175 \\ }
1205 \\ while (true) {1176 \\ while (true) {
1206 \\ var a_1: c_int = 2;1177 \\ var a_1: c_int = 2;
1207 \\ a_1 = 12;1178 \\ a_1 = 12;
1208 \\ if (!(4 != 0)) break;1179 \\ if (!(@as(c_int, 4) != 0)) break;
1209 \\ }1180 \\ }
1210 \\ while (true) {1181 \\ while (true) {
1211 \\ a = 7;1182 \\ a = 7;
1212 \\ if (!(4 != 0)) break;1183 \\ if (!(@as(c_int, 4) != 0)) break;
1213 \\ }1184 \\ }
1214 \\}1185 \\}
1215 });1186 });
...@@ -1227,21 +1198,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1227,21 +1198,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1227 \\ {1198 \\ {
1228 \\ var i: c_int = 2;1199 \\ var i: c_int = 2;
1229 \\ var b: c_int = 4;1200 \\ var b: c_int = 4;
1230 \\ while ((i + 2) != 0) : (i = 2) {1201 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
1231 \\ var a: c_int = 2;1202 \\ var a: c_int = 2;
1232 \\ a = 6;1203 \\ a = 6;
1233 \\ _ = 5;1204 \\ _ = @as(c_int, 5);
1234 \\ _ = 7;1205 \\ _ = @as(c_int, 7);
1235 \\ }1206 \\ }
1236 \\ }1207 \\ }
1237 \\ var i: u8 = @intCast(u8, 2);1208 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
1238 \\}1209 \\}
1239 });1210 });
12401211
1241 cases.add("shadowing primitive types",1212 cases.add("shadowing primitive types",
1242 \\unsigned anyerror = 2;1213 \\unsigned anyerror = 2;
1243 , &[_][]const u8{1214 , &[_][]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));
1245 });1216 });
12461217
1247 cases.add("floats",1218 cases.add("floats",
...@@ -1253,7 +1224,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1253,7 +1224,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1253 \\pub export var a: f32 = @floatCast(f32, 3.1415);1224 \\pub export var a: f32 = @floatCast(f32, 3.1415);
1254 \\pub export var b: f64 = 3.1415;1225 \\pub export var b: f64 = 3.1415;
1255 \\pub export var c: c_int = @floatToInt(c_int, 3.1415);1226 \\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));
1257 });1228 });
12581229
1259 cases.add("conditional operator",1230 cases.add("conditional operator",
...@@ -1263,8 +1234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1263,8 +1234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1263 \\}1234 \\}
1264 , &[_][]const u8{1235 , &[_][]const u8{
1265 \\pub export fn bar() c_int {1236 \\pub export fn bar() c_int {
1266 \\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2;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);
1267 \\ return if (2 != 0) 5 else if (5 != 0) 4 else 6;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);
1268 \\}1239 \\}
1269 });1240 });
12701241
...@@ -1303,7 +1274,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1303,7 +1274,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1303 \\ }1274 \\ }
1304 \\ res = 2;1275 \\ res = 2;
1305 \\ }1276 \\ }
1306 \\ res = (3 * i);1277 \\ res = (@as(c_int, 3) * i);
1307 \\ break :__switch;1278 \\ break :__switch;
1308 \\ }1279 \\ }
1309 \\ res = 5;1280 \\ res = 5;
...@@ -1397,6 +1368,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1397,6 +1368,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1397 \\}1368 \\}
1398 });1369 });
13991370
1371 // TODO translate-c should in theory be able to figure out to drop all these casts
1400 cases.add("escape sequences",1372 cases.add("escape sequences",
1401 \\const char *escapes() {1373 \\const char *escapes() {
1402 \\char a = '\'',1374 \\char a = '\'',
...@@ -1415,17 +1387,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1415,17 +1387,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1415 \\1387 \\
1416 , &[_][]const u8{1388 , &[_][]const u8{
1417 \\pub export fn escapes() [*c]const u8 {1389 \\pub export fn escapes() [*c]const u8 {
1418 \\ var a: u8 = @intCast(u8, '\'');1390 \\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));
1419 \\ var b: u8 = @intCast(u8, '\\');1391 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));
1420 \\ var c: u8 = @intCast(u8, '\x07');1392 \\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));
1421 \\ var d: u8 = @intCast(u8, '\x08');1393 \\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));
1422 \\ var e: u8 = @intCast(u8, '\x0c');1394 \\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));
1423 \\ var f: u8 = @intCast(u8, '\n');1395 \\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));
1424 \\ var g: u8 = @intCast(u8, '\r');1396 \\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));
1425 \\ var h: u8 = @intCast(u8, '\t');1397 \\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));
1426 \\ var i: u8 = @intCast(u8, '\x0b');1398 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));
1427 \\ var j: u8 = @intCast(u8, '\x00');1399 \\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));
1428 \\ var k: u8 = @intCast(u8, '\"');1400 \\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));
1429 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";1401 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
1430 \\}1402 \\}
1431 });1403 });
...@@ -1446,12 +1418,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1446,12 +1418,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1446 \\pub export fn foo() void {1418 \\pub export fn foo() void {
1447 \\ var a: c_int = 2;1419 \\ var a: c_int = 2;
1448 \\ while (true) {1420 \\ while (true) {
1449 \\ a = (a - 1);1421 \\ a = (a - @as(c_int, 1));
1450 \\ if (!(a != 0)) break;1422 \\ if (!(a != 0)) break;
1451 \\ }1423 \\ }
1452 \\ var b: c_int = 2;1424 \\ var b: c_int = 2;
1453 \\ while (true) {1425 \\ while (true) {
1454 \\ b = (b - 1);1426 \\ b = (b - @as(c_int, 1));
1455 \\ if (!(b != 0)) break;1427 \\ if (!(b != 0)) break;
1456 \\ }1428 \\ }
1457 \\}1429 \\}
...@@ -1602,7 +1574,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1602,7 +1574,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1602 \\pub const yes = [*c]u8;1574 \\pub const yes = [*c]u8;
1603 \\pub export fn foo() void {1575 \\pub export fn foo() void {
1604 \\ var a: yes = undefined;1576 \\ var a: yes = undefined;
1605 \\ if (a != null) _ = 2;1577 \\ if (a != null) _ = @as(c_int, 2);
1606 \\}1578 \\}
1607 });1579 });
16081580
...@@ -1695,7 +1667,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1695,7 +1667,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1695 \\}1667 \\}
1696 });1668 });
16971669
1698 cases.add("if statement",1670 cases.add("simple if statement",
1699 \\int max(int a, int b) {1671 \\int max(int a, int b) {
1700 \\ if (a < b)1672 \\ if (a < b)
1701 \\ return b;1673 \\ return b;
...@@ -1717,6 +1689,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1717,6 +1689,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1717 \\}1689 \\}
1718 });1690 });
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
1720 cases.add("if on non-bool",1715 cases.add("if on non-bool",
1721 \\enum SomeEnum { A, B, C };1716 \\enum SomeEnum { A, B, C };
1722 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {1717 \\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
...@@ -1764,7 +1759,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1764,7 +1759,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1764 , &[_][]const u8{1759 , &[_][]const u8{
1765 \\pub export fn abs(arg_a: c_int) c_int {1760 \\pub export fn abs(arg_a: c_int) c_int {
1766 \\ var a = arg_a;1761 \\ var a = arg_a;
1767 \\ return if (a < 0) -a else a;1762 \\ return if (a < @as(c_int, 0)) -a else a;
1768 \\}1763 \\}
1769 });1764 });
17701765
...@@ -1845,7 +1840,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1845,7 +1840,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1845 , &[_][]const u8{1840 , &[_][]const u8{
1846 \\pub export fn foo() void {1841 \\pub export fn foo() void {
1847 \\ var i: c_int = 0;1842 \\ 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));
1849 \\ i += 1;1844 \\ i += 1;
1850 \\ i -= 1;1845 \\ i -= 1;
1851 \\ u +%= 1;1846 \\ u +%= 1;
...@@ -1885,7 +1880,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1885,7 +1880,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1885 \\pub export fn log2(arg_a: c_uint) c_int {1880 \\pub export fn log2(arg_a: c_uint) c_int {
1886 \\ var a = arg_a;1881 \\ var a = arg_a;
1887 \\ var i: c_int = 0;1882 \\ var i: c_int = 0;
1888 \\ while (a > @intCast(c_uint, 0)) {1883 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
1889 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);1884 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
1890 \\ }1885 \\ }
1891 \\ return i;1886 \\ return i;
...@@ -1905,7 +1900,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1905,7 +1900,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1905 \\pub export fn log2(arg_a: u32) c_int {1900 \\pub export fn log2(arg_a: u32) c_int {
1906 \\ var a = arg_a;1901 \\ var a = arg_a;
1907 \\ var i: c_int = 0;1902 \\ var i: c_int = 0;
1908 \\ while (a > @intCast(c_uint, 0)) {1903 \\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
1909 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);1904 \\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
1910 \\ }1905 \\ }
1911 \\ return i;1906 \\ return i;
...@@ -1929,42 +1924,42 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1929,42 +1924,42 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1929 \\ var a: c_int = 0;1924 \\ var a: c_int = 0;
1930 \\ a += (blk: {1925 \\ a += (blk: {
1931 \\ const ref = &a;1926 \\ const ref = &a;
1932 \\ ref.* = ref.* + 1;1927 \\ ref.* = ref.* + @as(c_int, 1);
1933 \\ break :blk ref.*;1928 \\ break :blk ref.*;
1934 \\ });1929 \\ });
1935 \\ a -= (blk: {1930 \\ a -= (blk: {
1936 \\ const ref = &a;1931 \\ const ref = &a;
1937 \\ ref.* = ref.* - 1;1932 \\ ref.* = ref.* - @as(c_int, 1);
1938 \\ break :blk ref.*;1933 \\ break :blk ref.*;
1939 \\ });1934 \\ });
1940 \\ a *= (blk: {1935 \\ a *= (blk: {
1941 \\ const ref = &a;1936 \\ const ref = &a;
1942 \\ ref.* = ref.* * 1;1937 \\ ref.* = ref.* * @as(c_int, 1);
1943 \\ break :blk ref.*;1938 \\ break :blk ref.*;
1944 \\ });1939 \\ });
1945 \\ a &= (blk: {1940 \\ a &= (blk: {
1946 \\ const ref = &a;1941 \\ const ref = &a;
1947 \\ ref.* = ref.* & 1;1942 \\ ref.* = ref.* & @as(c_int, 1);
1948 \\ break :blk ref.*;1943 \\ break :blk ref.*;
1949 \\ });1944 \\ });
1950 \\ a |= (blk: {1945 \\ a |= (blk: {
1951 \\ const ref = &a;1946 \\ const ref = &a;
1952 \\ ref.* = ref.* | 1;1947 \\ ref.* = ref.* | @as(c_int, 1);
1953 \\ break :blk ref.*;1948 \\ break :blk ref.*;
1954 \\ });1949 \\ });
1955 \\ a ^= (blk: {1950 \\ a ^= (blk: {
1956 \\ const ref = &a;1951 \\ const ref = &a;
1957 \\ ref.* = ref.* ^ 1;1952 \\ ref.* = ref.* ^ @as(c_int, 1);
1958 \\ break :blk ref.*;1953 \\ break :blk ref.*;
1959 \\ });1954 \\ });
1960 \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {1955 \\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
1961 \\ const ref = &a;1956 \\ 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));
1963 \\ break :blk ref.*;1958 \\ break :blk ref.*;
1964 \\ }));1959 \\ }));
1965 \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {1960 \\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
1966 \\ const ref = &a;1961 \\ 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));
1968 \\ break :blk ref.*;1963 \\ break :blk ref.*;
1969 \\ }));1964 \\ }));
1970 \\}1965 \\}
...@@ -1984,45 +1979,45 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1984,45 +1979,45 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1984 \\}1979 \\}
1985 , &[_][]const u8{1980 , &[_][]const u8{
1986 \\pub export fn foo() void {1981 \\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));
1988 \\ a +%= (blk: {1983 \\ a +%= (blk: {
1989 \\ const ref = &a;1984 \\ const ref = &a;
1990 \\ ref.* = ref.* +% @intCast(c_uint, 1);1985 \\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));
1991 \\ break :blk ref.*;1986 \\ break :blk ref.*;
1992 \\ });1987 \\ });
1993 \\ a -%= (blk: {1988 \\ a -%= (blk: {
1994 \\ const ref = &a;1989 \\ const ref = &a;
1995 \\ ref.* = ref.* -% @intCast(c_uint, 1);1990 \\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));
1996 \\ break :blk ref.*;1991 \\ break :blk ref.*;
1997 \\ });1992 \\ });
1998 \\ a *%= (blk: {1993 \\ a *%= (blk: {
1999 \\ const ref = &a;1994 \\ const ref = &a;
2000 \\ ref.* = ref.* *% @intCast(c_uint, 1);1995 \\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));
2001 \\ break :blk ref.*;1996 \\ break :blk ref.*;
2002 \\ });1997 \\ });
2003 \\ a &= (blk: {1998 \\ a &= (blk: {
2004 \\ const ref = &a;1999 \\ const ref = &a;
2005 \\ ref.* = ref.* & @intCast(c_uint, 1);2000 \\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));
2006 \\ break :blk ref.*;2001 \\ break :blk ref.*;
2007 \\ });2002 \\ });
2008 \\ a |= (blk: {2003 \\ a |= (blk: {
2009 \\ const ref = &a;2004 \\ const ref = &a;
2010 \\ ref.* = ref.* | @intCast(c_uint, 1);2005 \\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));
2011 \\ break :blk ref.*;2006 \\ break :blk ref.*;
2012 \\ });2007 \\ });
2013 \\ a ^= (blk: {2008 \\ a ^= (blk: {
2014 \\ const ref = &a;2009 \\ const ref = &a;
2015 \\ ref.* = ref.* ^ @intCast(c_uint, 1);2010 \\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));
2016 \\ break :blk ref.*;2011 \\ break :blk ref.*;
2017 \\ });2012 \\ });
2018 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {2013 \\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
2019 \\ const ref = &a;2014 \\ 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));
2021 \\ break :blk ref.*;2016 \\ break :blk ref.*;
2022 \\ }));2017 \\ }));
2023 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {2018 \\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
2024 \\ const ref = &a;2019 \\ 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));
2026 \\ break :blk ref.*;2021 \\ break :blk ref.*;
2027 \\ }));2022 \\ }));
2028 \\}2023 \\}
...@@ -2044,7 +2039,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2044,7 +2039,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2044 , &[_][]const u8{2039 , &[_][]const u8{
2045 \\pub export fn foo() void {2040 \\pub export fn foo() void {
2046 \\ var i: c_int = 0;2041 \\ 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));
2048 \\ i += 1;2043 \\ i += 1;
2049 \\ i -= 1;2044 \\ i -= 1;
2050 \\ u +%= 1;2045 \\ u +%= 1;
...@@ -2115,19 +2110,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2115,19 +2110,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2115 \\ fn_int(@floatToInt(c_int, 3));2110 \\ fn_int(@floatToInt(c_int, 3));
2116 \\ fn_int(@floatToInt(c_int, 3));2111 \\ fn_int(@floatToInt(c_int, 3));
2117 \\ fn_int(@floatToInt(c_int, 3));2112 \\ fn_int(@floatToInt(c_int, 3));
2118 \\ fn_int(1094861636);2113 \\ fn_int(@as(c_int, 1094861636));
2119 \\ fn_f32(@intToFloat(f32, 3));2114 \\ fn_f32(@intToFloat(f32, @as(c_int, 3)));
2120 \\ fn_f64(@intToFloat(f64, 3));2115 \\ fn_f64(@intToFloat(f64, @as(c_int, 3)));
2121 \\ fn_char(@intCast(u8, '3'));2116 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3'))));
2122 \\ fn_char(@intCast(u8, '\x01'));2117 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01'))));
2123 \\ fn_char(@intCast(u8, 0));2118 \\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0))));
2124 \\ fn_f32(3);2119 \\ fn_f32(3);
2125 \\ fn_f64(3);2120 \\ fn_f64(3);
2126 \\ fn_bool(123 != 0);2121 \\ fn_bool(@as(c_int, 123) != 0);
2127 \\ fn_bool(0 != 0);2122 \\ fn_bool(@as(c_int, 0) != 0);
2128 \\ fn_bool(@ptrToInt(&fn_int) != 0);2123 \\ fn_bool(@ptrToInt(&fn_int) != 0);
2129 \\ fn_int(@intCast(c_int, @ptrToInt(&fn_int)));2124 \\ 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)));
2131 \\}2126 \\}
2132 });2127 });
21332128
...@@ -2223,8 +2218,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2223,8 +2218,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2223 \\}2218 \\}
2224 , &[_][]const u8{2219 , &[_][]const u8{
2225 \\pub fn foo() void {2220 \\pub fn foo() void {
2226 \\ if (1 != 0) while (true) {2221 \\ if (@as(c_int, 1) != 0) while (true) {
2227 \\ if (!(0 != 0)) break;2222 \\ if (!(@as(c_int, 0) != 0)) break;
2228 \\ };2223 \\ };
2229 \\}2224 \\}
2230 });2225 });
...@@ -2263,4 +2258,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2263,4 +2258,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2263 \\ };2258 \\ };
2264 \\}2259 \\}
2265 });2260 });
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 });
2266}2278}