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.
This commit is contained in:
parent
5575e2a168
commit
dc28526c6c
@ -804,8 +804,8 @@ pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *cons
|
||||
pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation;
|
||||
pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass;
|
||||
pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool;
|
||||
pub extern fn ZigClangExpr_getStmtClass(self: ?*const struct_ZigClangExpr) ZigClangStmtClass;
|
||||
pub extern fn ZigClangExpr_getType(self: ?*const struct_ZigClangExpr) struct_ZigClangQualType;
|
||||
pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass;
|
||||
pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType;
|
||||
pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation;
|
||||
pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr;
|
||||
pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr;
|
||||
|
@ -9,6 +9,7 @@ usingnamespace @import("clang.zig");
|
||||
const ctok = @import("c_tokenizer.zig");
|
||||
const CToken = ctok.CToken;
|
||||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
|
||||
const CallingConvention = std.builtin.TypeInfo.CallingConvention;
|
||||
|
||||
@ -498,10 +499,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
|
||||
var eq_tok: ast.TokenIndex = undefined;
|
||||
var init_node: ?*ast.Node = null;
|
||||
|
||||
// If the initialization expression is not present, initialize with undefined.
|
||||
// If it is an integer literal, we can skip the @as since it will be redundant
|
||||
// with the variable type.
|
||||
if (ZigClangVarDecl_hasInit(var_decl)) {
|
||||
eq_tok = try appendToken(c, .Equal, "=");
|
||||
init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
||||
transExpr(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
|
||||
transExprCoercing(rp, &c.global_scope.base, expr, .used, .r_value) catch |err| switch (err) {
|
||||
error.UnsupportedTranslation,
|
||||
error.UnsupportedType,
|
||||
=> {
|
||||
@ -857,7 +861,7 @@ fn transStmt(
|
||||
.DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)),
|
||||
.DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue),
|
||||
.ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used),
|
||||
.IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used),
|
||||
.IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used, .with_as),
|
||||
.ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)),
|
||||
.StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
|
||||
.ParenExprClass => {
|
||||
@ -891,7 +895,7 @@ fn transStmt(
|
||||
.DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
|
||||
.ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
|
||||
.PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),
|
||||
.CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used),
|
||||
.CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used, .with_as),
|
||||
.StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const ZigClangStmtExpr, stmt), result_used),
|
||||
.MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const ZigClangMemberExpr, stmt), result_used),
|
||||
.ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
|
||||
@ -1160,7 +1164,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt)
|
||||
|
||||
node.eq_token = try appendToken(c, .Equal, "=");
|
||||
var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr|
|
||||
try transExpr(rp, scope, expr, .used, .r_value)
|
||||
try transExprCoercing(rp, scope, expr, .used, .r_value)
|
||||
else
|
||||
try transCreateNodeUndefinedLiteral(c);
|
||||
if (isBoolRes(init_node)) {
|
||||
@ -1391,19 +1395,50 @@ fn finishBoolExpr(
|
||||
return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
|
||||
}
|
||||
|
||||
const SuppressCast = enum {
|
||||
with_as,
|
||||
no_as,
|
||||
};
|
||||
fn transIntegerLiteral(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
expr: *const ZigClangIntegerLiteral,
|
||||
result_used: ResultUsed,
|
||||
suppress_as: SuppressCast,
|
||||
) TransError!*ast.Node {
|
||||
var eval_result: ZigClangExprEvalResult = undefined;
|
||||
if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) {
|
||||
const loc = ZigClangIntegerLiteral_getBeginLoc(expr);
|
||||
return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
|
||||
}
|
||||
const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
|
||||
return maybeSuppressResult(rp, scope, result_used, node);
|
||||
|
||||
if (suppress_as == .no_as) {
|
||||
const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
|
||||
return maybeSuppressResult(rp, scope, result_used, int_lit_node);
|
||||
}
|
||||
|
||||
// Integer literals in C have types, and this can matter for several reasons.
|
||||
// For example, this is valid C:
|
||||
// unsigned char y = 256;
|
||||
// How this gets evaluated is the 256 is an integer, which gets truncated to signed char, then bit-casted
|
||||
// to unsigned char, resulting in 0. In order for this to work, we have to emit this zig code:
|
||||
// var y = @bitCast(u8, @truncate(i8, @as(c_int, 256)));
|
||||
// Ideally in translate-c we could flatten this out to simply:
|
||||
// var y: u8 = 0;
|
||||
// But the first step is to be correct, and the next step is to make the output more elegant.
|
||||
|
||||
// @as(T, x)
|
||||
const expr_base = @ptrCast(*const ZigClangExpr, expr);
|
||||
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
|
||||
try as_node.params.push(ty_node);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
|
||||
const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val));
|
||||
try as_node.params.push(int_lit_node);
|
||||
|
||||
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
return maybeSuppressResult(rp, scope, result_used, &as_node.base);
|
||||
}
|
||||
|
||||
fn transReturnStmt(
|
||||
@ -1413,7 +1448,7 @@ fn transReturnStmt(
|
||||
) TransError!*ast.Node {
|
||||
const node = try transCreateNodeReturnExpr(rp.c);
|
||||
if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {
|
||||
node.rhs = try transExpr(rp, scope, val_expr, .used, .r_value);
|
||||
node.rhs = try transExprCoercing(rp, scope, val_expr, .used, .r_value);
|
||||
}
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return &node.base;
|
||||
@ -1502,11 +1537,41 @@ fn transCCast(
|
||||
if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
|
||||
return transCPtrCast(rp, loc, dst_type, src_type, expr);
|
||||
if (cIsInteger(dst_type) and cIsInteger(src_type)) {
|
||||
// @intCast(dest_type, val)
|
||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast");
|
||||
// 1. Extend or truncate without changing signed-ness.
|
||||
// 2. Bit-cast to correct signed-ness
|
||||
|
||||
// @bitCast(dest_type, intermediate_value)
|
||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
|
||||
try cast_node.params.push(try transQualType(rp, dst_type, loc));
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try cast_node.params.push(expr);
|
||||
|
||||
switch (cIntTypeCmp(dst_type, src_type)) {
|
||||
.lt => {
|
||||
// @truncate(SameSignSmallerInt, src_type)
|
||||
const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate");
|
||||
const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
|
||||
try trunc_node.params.push(ty_node);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try trunc_node.params.push(expr);
|
||||
trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
try cast_node.params.push(&trunc_node.base);
|
||||
},
|
||||
.gt => {
|
||||
// @as(SameSignBiggerInt, src_type)
|
||||
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type));
|
||||
try as_node.params.push(ty_node);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
try as_node.params.push(expr);
|
||||
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
try cast_node.params.push(&as_node.base);
|
||||
},
|
||||
.eq => {
|
||||
try cast_node.params.push(expr);
|
||||
},
|
||||
}
|
||||
cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
return &cast_node.base;
|
||||
}
|
||||
@ -1579,9 +1644,6 @@ fn transCCast(
|
||||
builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
return &builtin_node.base;
|
||||
}
|
||||
// TODO: maybe widen to increase size
|
||||
// TODO: maybe bitcast to change sign
|
||||
// TODO: maybe truncate to reduce size
|
||||
const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
try cast_node.params.push(try transQualType(rp, dst_type, loc));
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
@ -1600,6 +1662,33 @@ fn transExpr(
|
||||
return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue);
|
||||
}
|
||||
|
||||
/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
|
||||
/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
|
||||
fn transExprCoercing(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
expr: *const ZigClangExpr,
|
||||
used: ResultUsed,
|
||||
lrvalue: LRValue,
|
||||
) TransError!*ast.Node {
|
||||
switch (ZigClangStmt_getStmtClass(@ptrCast(*const ZigClangStmt, expr))) {
|
||||
.IntegerLiteralClass => {
|
||||
return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, expr), .used, .no_as);
|
||||
},
|
||||
.CharacterLiteralClass => {
|
||||
return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, expr), .used, .no_as);
|
||||
},
|
||||
.UnaryOperatorClass => {
|
||||
const un_expr = @ptrCast(*const ZigClangUnaryOperator, expr);
|
||||
if (ZigClangUnaryOperator_getOpcode(un_expr) == .Extension) {
|
||||
return transExprCoercing(rp, scope, ZigClangUnaryOperator_getSubExpr(un_expr), used, lrvalue);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return transExpr(rp, scope, expr, .used, .r_value);
|
||||
}
|
||||
|
||||
fn transInitListExpr(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
@ -1625,7 +1714,7 @@ fn transInitListExpr(
|
||||
const init_count = ZigClangInitListExpr_getNumInits(expr);
|
||||
const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type);
|
||||
const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
|
||||
const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
|
||||
const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
|
||||
const leftover_count = all_count - init_count;
|
||||
|
||||
var init_node: *ast.Node.SuffixOp = undefined;
|
||||
@ -2033,16 +2122,17 @@ fn transCharLiteral(
|
||||
scope: *Scope,
|
||||
stmt: *const ZigClangCharacterLiteral,
|
||||
result_used: ResultUsed,
|
||||
suppress_as: SuppressCast,
|
||||
) TransError!*ast.Node {
|
||||
const kind = ZigClangCharacterLiteral_getKind(stmt);
|
||||
switch (kind) {
|
||||
.Ascii, .UTF8 => {
|
||||
const int_lit_node = switch (kind) {
|
||||
.Ascii, .UTF8 => blk: {
|
||||
const val = ZigClangCharacterLiteral_getValue(stmt);
|
||||
if (kind == .Ascii) {
|
||||
// C has a somewhat obscure feature called multi-character character
|
||||
// constant
|
||||
if (val > 255)
|
||||
return transCreateNodeInt(rp.c, val);
|
||||
break :blk try transCreateNodeInt(rp.c, val);
|
||||
}
|
||||
var char_buf: [4]u8 = undefined;
|
||||
const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
|
||||
@ -2050,7 +2140,7 @@ fn transCharLiteral(
|
||||
node.* = .{
|
||||
.token = token,
|
||||
};
|
||||
return maybeSuppressResult(rp, scope, result_used, &node.base);
|
||||
break :blk &node.base;
|
||||
},
|
||||
.UTF16, .UTF32, .Wide => return revertAndWarn(
|
||||
rp,
|
||||
@ -2060,7 +2150,22 @@ fn transCharLiteral(
|
||||
.{kind},
|
||||
),
|
||||
else => unreachable,
|
||||
};
|
||||
if (suppress_as == .no_as) {
|
||||
return maybeSuppressResult(rp, scope, result_used, int_lit_node);
|
||||
}
|
||||
// See comment in `transIntegerLiteral` for why this code is here.
|
||||
// @as(T, x)
|
||||
const expr_base = @ptrCast(*const ZigClangExpr, stmt);
|
||||
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base));
|
||||
try as_node.params.push(ty_node);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
|
||||
try as_node.params.push(int_lit_node);
|
||||
|
||||
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
return maybeSuppressResult(rp, scope, result_used, &as_node.base);
|
||||
}
|
||||
|
||||
fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, used: ResultUsed) TransError!*ast.Node {
|
||||
@ -2480,7 +2585,10 @@ fn transCreateCompoundAssign(
|
||||
// zig: lhs += rhs
|
||||
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||
const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
|
||||
var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
|
||||
var rhs_node = if (is_shift)
|
||||
try transExprCoercing(rp, scope, rhs, .used, .r_value)
|
||||
else
|
||||
try transExpr(rp, scope, rhs, .used, .r_value);
|
||||
|
||||
if (is_shift) {
|
||||
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
|
||||
@ -2681,6 +2789,30 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou
|
||||
return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc);
|
||||
}
|
||||
|
||||
/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
|
||||
/// Asserts the type is an integer.
|
||||
fn transQualTypeIntWidthOf(c: *Context, ty: ZigClangQualType, is_signed: bool) TypeError!*ast.Node {
|
||||
return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
|
||||
}
|
||||
|
||||
/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
|
||||
/// Asserts the type is an integer.
|
||||
fn transTypeIntWidthOf(c: *Context, ty: *const ZigClangType, is_signed: bool) TypeError!*ast.Node {
|
||||
assert(ZigClangType_getTypeClass(ty) == .Builtin);
|
||||
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
|
||||
return transCreateNodeIdentifier(c, switch (ZigClangBuiltinType_getKind(builtin_ty)) {
|
||||
.Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",
|
||||
.UShort, .Short => if (is_signed) "c_short" else "c_ushort",
|
||||
.UInt, .Int => if (is_signed) "c_int" else "c_uint",
|
||||
.ULong, .Long => if (is_signed) "c_long" else "c_ulong",
|
||||
.ULongLong, .LongLong => if (is_signed) "c_longlong" else "c_ulonglong",
|
||||
.UInt128, .Int128 => if (is_signed) "i128" else "u128",
|
||||
.Char16 => if (is_signed) "i16" else "u16",
|
||||
.Char32 => if (is_signed) "i32" else "u32",
|
||||
else => unreachable, // only call this function when it has already been determined the type is int
|
||||
});
|
||||
}
|
||||
|
||||
fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool {
|
||||
const c_type = qualTypeCanon(qt);
|
||||
if (ZigClangType_getTypeClass(c_type) != .Builtin)
|
||||
@ -2742,7 +2874,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
|
||||
|
||||
if (int_bit_width != 0) {
|
||||
// we can perform the log2 now.
|
||||
const cast_bit_width = std.math.log2_int(u64, int_bit_width);
|
||||
const cast_bit_width = math.log2_int(u64, int_bit_width);
|
||||
const node = try rp.c.a().create(ast.Node.IntegerLiteral);
|
||||
node.* = ast.Node.IntegerLiteral{
|
||||
.token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
|
||||
@ -2902,6 +3034,28 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
|
||||
};
|
||||
}
|
||||
|
||||
fn cIntTypeToIndex(qt: ZigClangQualType) u8 {
|
||||
const c_type = qualTypeCanon(qt);
|
||||
assert(ZigClangType_getTypeClass(c_type) == .Builtin);
|
||||
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
|
||||
return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
|
||||
.Bool, .Char_U, .Char_S, .UChar, .SChar, .Char8 => 1,
|
||||
.WChar_U, .WChar_S => 2,
|
||||
.UShort, .Short, .Char16 => 3,
|
||||
.UInt, .Int, .Char32 => 4,
|
||||
.ULong, .Long => 5,
|
||||
.ULongLong, .LongLong => 6,
|
||||
.UInt128, .Int128 => 7,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn cIntTypeCmp(a: ZigClangQualType, b: ZigClangQualType) math.Order {
|
||||
const a_index = cIntTypeToIndex(a);
|
||||
const b_index = cIntTypeToIndex(b);
|
||||
return math.order(a_index, b_index);
|
||||
}
|
||||
|
||||
fn cIsSignedInteger(qt: ZigClangQualType) bool {
|
||||
const c_type = qualTypeCanon(qt);
|
||||
if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
|
||||
@ -2946,7 +3100,7 @@ fn transCreateNodeAssign(
|
||||
if (result_used == .unused) {
|
||||
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
|
||||
const eq_token = try appendToken(rp.c, .Equal, "=");
|
||||
var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
|
||||
var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
|
||||
if (isBoolRes(rhs_node)) {
|
||||
const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt");
|
||||
try builtin_node.params.push(rhs_node);
|
||||
@ -3158,7 +3312,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
|
||||
const is_negative = ZigClangAPSInt_isSigned(int) and ZigClangAPSInt_isNegative(int);
|
||||
if (is_negative)
|
||||
aps_int = ZigClangAPSInt_negate(aps_int);
|
||||
var big = try std.math.big.Int.initCapacity(c.a(), num_limbs);
|
||||
var big = try math.big.Int.initCapacity(c.a(), num_limbs);
|
||||
if (is_negative)
|
||||
big.negate();
|
||||
defer big.deinit();
|
||||
@ -3522,7 +3676,7 @@ fn transCreateNodeShiftOp(
|
||||
const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
|
||||
try as_node.params.push(rhs_type);
|
||||
_ = try appendToken(rp.c, .Comma, ",");
|
||||
const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
|
||||
const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
|
||||
try as_node.params.push(rhs);
|
||||
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
|
||||
|
||||
@ -3652,7 +3806,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
|
||||
const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, ty);
|
||||
|
||||
const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty);
|
||||
const size = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize));
|
||||
const size = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize));
|
||||
var node = try transCreateNodePrefixOp(
|
||||
rp.c,
|
||||
.{
|
||||
|
@ -17,13 +17,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ char b = 123;
|
||||
\\ const int c;
|
||||
\\ const unsigned d = 440;
|
||||
\\ int e = 10;
|
||||
\\ unsigned int f = 10u;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_int = undefined;
|
||||
\\ var b: u8 = @intCast(u8, 123);
|
||||
\\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
|
||||
\\ const c: c_int = undefined;
|
||||
\\ const d: c_uint = @intCast(c_uint, 440);
|
||||
\\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440));
|
||||
\\ var e: c_int = 10;
|
||||
\\ var f: c_uint = 10;
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -39,14 +43,24 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_int = undefined;
|
||||
\\ _ = 1;
|
||||
\\ _ = @as(c_int, 1);
|
||||
\\ _ = "hey";
|
||||
\\ _ = (1 + 1);
|
||||
\\ _ = (1 - 1);
|
||||
\\ _ = (@as(c_int, 1) + @as(c_int, 1));
|
||||
\\ _ = (@as(c_int, 1) - @as(c_int, 1));
|
||||
\\ a = 1;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("function with no prototype",
|
||||
\\int foo() {
|
||||
\\ return 5;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ return 5;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("variables",
|
||||
\\extern int extern_var;
|
||||
\\static const int int_var = 13;
|
||||
@ -474,26 +488,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("ignore result, no function arguments",
|
||||
\\void foo() {
|
||||
\\ int a;
|
||||
\\ 1;
|
||||
\\ "hey";
|
||||
\\ 1 + 1;
|
||||
\\ 1 - 1;
|
||||
\\ a = 1;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_int = undefined;
|
||||
\\ _ = 1;
|
||||
\\ _ = "hey";
|
||||
\\ _ = (1 + 1);
|
||||
\\ _ = (1 - 1);
|
||||
\\ a = 1;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("constant size array",
|
||||
\\void func(int array[20]);
|
||||
, &[_][]const u8{
|
||||
@ -582,7 +576,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export fn foo() void {
|
||||
\\ {
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (i != 0) : (i = (i + 1)) {}
|
||||
\\ while (i != 0) : (i = (i + @as(c_int, 1))) {}
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
@ -721,7 +715,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ return (1 << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ return (@as(c_int, 1) << @as(@import("std").math.Log2Int(c_int), 2)) >> @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -789,7 +783,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ var a: c_int = undefined;
|
||||
\\ var b: f32 = undefined;
|
||||
\\ var c: ?*c_void = undefined;
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a == @as(c_int, 0));
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
@ -864,7 +858,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo() void {
|
||||
\\ var arr: [10]u8 = .{
|
||||
\\ @intCast(u8, 1),
|
||||
\\ @bitCast(u8, @truncate(i8, @as(c_int, 1))),
|
||||
\\ } ++ .{0} ** 9;
|
||||
\\ var arr1: [10][*c]u8 = .{
|
||||
\\ null,
|
||||
@ -1103,18 +1097,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ unsigned d = 440;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub var a: c_long = @intCast(c_long, 2);
|
||||
\\pub var b: c_long = @intCast(c_long, 2);
|
||||
\\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
|
||||
\\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
|
||||
\\pub var c: c_int = 4;
|
||||
\\pub export fn foo(arg_c_1: u8) void {
|
||||
\\ var c_1 = arg_c_1;
|
||||
\\ var a_2: c_int = undefined;
|
||||
\\ var b_3: u8 = @intCast(u8, 123);
|
||||
\\ b_3 = @intCast(u8, a_2);
|
||||
\\ var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
|
||||
\\ b_3 = @bitCast(u8, @truncate(i8, a_2));
|
||||
\\ {
|
||||
\\ var d: c_int = 5;
|
||||
\\ }
|
||||
\\ var d: c_uint = @intCast(c_uint, 440);
|
||||
\\ var d: c_uint = @bitCast(c_uint, @as(c_int, 440));
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -1125,11 +1119,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ _ = 2;
|
||||
\\ _ = 4;
|
||||
\\ _ = 2;
|
||||
\\ _ = 4;
|
||||
\\ return 6;
|
||||
\\ _ = @as(c_int, 2);
|
||||
\\ _ = @as(c_int, 4);
|
||||
\\ _ = @as(c_int, 2);
|
||||
\\ _ = @as(c_int, 4);
|
||||
\\ return @as(c_int, 6);
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -1144,36 +1138,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ var a: c_int = undefined;
|
||||
\\ var b: c_int = undefined;
|
||||
\\ a = blk: {
|
||||
\\ const tmp = 2;
|
||||
\\ const tmp = @as(c_int, 2);
|
||||
\\ b = tmp;
|
||||
\\ break :blk tmp;
|
||||
\\ };
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("if statements",
|
||||
\\int foo() {
|
||||
\\ if (2) {
|
||||
\\ int a = 2;
|
||||
\\ }
|
||||
\\ if (2, 5) {
|
||||
\\ int a = 2;
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ if (2 != 0) {
|
||||
\\ var a: c_int = 2;
|
||||
\\ }
|
||||
\\ if ((blk: {
|
||||
\\ _ = 2;
|
||||
\\ break :blk 5;
|
||||
\\ }) != 0) {
|
||||
\\ var a: c_int = 2;
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("while loops",
|
||||
\\int foo() {
|
||||
\\ int a = 5;
|
||||
@ -1195,21 +1166,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ var a: c_int = 5;
|
||||
\\ while (2 != 0) a = 2;
|
||||
\\ while (4 != 0) {
|
||||
\\ while (@as(c_int, 2) != 0) a = 2;
|
||||
\\ while (@as(c_int, 4) != 0) {
|
||||
\\ var a_1: c_int = 4;
|
||||
\\ a_1 = 9;
|
||||
\\ _ = 6;
|
||||
\\ _ = @as(c_int, 6);
|
||||
\\ return a_1;
|
||||
\\ }
|
||||
\\ while (true) {
|
||||
\\ var a_1: c_int = 2;
|
||||
\\ a_1 = 12;
|
||||
\\ if (!(4 != 0)) break;
|
||||
\\ if (!(@as(c_int, 4) != 0)) break;
|
||||
\\ }
|
||||
\\ while (true) {
|
||||
\\ a = 7;
|
||||
\\ if (!(4 != 0)) break;
|
||||
\\ if (!(@as(c_int, 4) != 0)) break;
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
@ -1227,21 +1198,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ {
|
||||
\\ var i: c_int = 2;
|
||||
\\ var b: c_int = 4;
|
||||
\\ while ((i + 2) != 0) : (i = 2) {
|
||||
\\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
|
||||
\\ var a: c_int = 2;
|
||||
\\ a = 6;
|
||||
\\ _ = 5;
|
||||
\\ _ = 7;
|
||||
\\ _ = @as(c_int, 5);
|
||||
\\ _ = @as(c_int, 7);
|
||||
\\ }
|
||||
\\ }
|
||||
\\ var i: u8 = @intCast(u8, 2);
|
||||
\\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("shadowing primitive types",
|
||||
\\unsigned anyerror = 2;
|
||||
, &[_][]const u8{
|
||||
\\pub export var _anyerror: c_uint = @intCast(c_uint, 2);
|
||||
\\pub export var _anyerror: c_uint = @bitCast(c_uint, @as(c_int, 2));
|
||||
});
|
||||
|
||||
cases.add("floats",
|
||||
@ -1253,7 +1224,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export var a: f32 = @floatCast(f32, 3.1415);
|
||||
\\pub export var b: f64 = 3.1415;
|
||||
\\pub export var c: c_int = @floatToInt(c_int, 3.1415);
|
||||
\\pub export var d: f64 = @intToFloat(f64, 3);
|
||||
\\pub export var d: f64 = @intToFloat(f64, @as(c_int, 3));
|
||||
});
|
||||
|
||||
cases.add("conditional operator",
|
||||
@ -1263,8 +1234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn bar() c_int {
|
||||
\\ if ((if (2 != 0) 5 else (if (5 != 0) 4 else 6)) != 0) _ = 2;
|
||||
\\ return if (2 != 0) 5 else if (5 != 0) 4 else 6;
|
||||
\\ 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);
|
||||
\\ 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);
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -1303,7 +1274,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ }
|
||||
\\ res = 2;
|
||||
\\ }
|
||||
\\ res = (3 * i);
|
||||
\\ res = (@as(c_int, 3) * i);
|
||||
\\ break :__switch;
|
||||
\\ }
|
||||
\\ res = 5;
|
||||
@ -1397,6 +1368,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
// TODO translate-c should in theory be able to figure out to drop all these casts
|
||||
cases.add("escape sequences",
|
||||
\\const char *escapes() {
|
||||
\\char a = '\'',
|
||||
@ -1415,17 +1387,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\
|
||||
, &[_][]const u8{
|
||||
\\pub export fn escapes() [*c]const u8 {
|
||||
\\ var a: u8 = @intCast(u8, '\'');
|
||||
\\ var b: u8 = @intCast(u8, '\\');
|
||||
\\ var c: u8 = @intCast(u8, '\x07');
|
||||
\\ var d: u8 = @intCast(u8, '\x08');
|
||||
\\ var e: u8 = @intCast(u8, '\x0c');
|
||||
\\ var f: u8 = @intCast(u8, '\n');
|
||||
\\ var g: u8 = @intCast(u8, '\r');
|
||||
\\ var h: u8 = @intCast(u8, '\t');
|
||||
\\ var i: u8 = @intCast(u8, '\x0b');
|
||||
\\ var j: u8 = @intCast(u8, '\x00');
|
||||
\\ var k: u8 = @intCast(u8, '\"');
|
||||
\\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));
|
||||
\\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));
|
||||
\\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));
|
||||
\\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));
|
||||
\\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));
|
||||
\\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));
|
||||
\\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));
|
||||
\\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));
|
||||
\\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));
|
||||
\\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));
|
||||
\\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));
|
||||
\\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
|
||||
\\}
|
||||
});
|
||||
@ -1446,12 +1418,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_int = 2;
|
||||
\\ while (true) {
|
||||
\\ a = (a - 1);
|
||||
\\ a = (a - @as(c_int, 1));
|
||||
\\ if (!(a != 0)) break;
|
||||
\\ }
|
||||
\\ var b: c_int = 2;
|
||||
\\ while (true) {
|
||||
\\ b = (b - 1);
|
||||
\\ b = (b - @as(c_int, 1));
|
||||
\\ if (!(b != 0)) break;
|
||||
\\ }
|
||||
\\}
|
||||
@ -1602,7 +1574,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub const yes = [*c]u8;
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: yes = undefined;
|
||||
\\ if (a != null) _ = 2;
|
||||
\\ if (a != null) _ = @as(c_int, 2);
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -1695,7 +1667,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("if statement",
|
||||
cases.add("simple if statement",
|
||||
\\int max(int a, int b) {
|
||||
\\ if (a < b)
|
||||
\\ return b;
|
||||
@ -1717,6 +1689,29 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("if statements",
|
||||
\\int foo() {
|
||||
\\ if (2) {
|
||||
\\ int a = 2;
|
||||
\\ }
|
||||
\\ if (2, 5) {
|
||||
\\ int a = 2;
|
||||
\\ }
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ if (@as(c_int, 2) != 0) {
|
||||
\\ var a: c_int = 2;
|
||||
\\ }
|
||||
\\ if ((blk: {
|
||||
\\ _ = @as(c_int, 2);
|
||||
\\ break :blk @as(c_int, 5);
|
||||
\\ }) != 0) {
|
||||
\\ var a: c_int = 2;
|
||||
\\ }
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("if on non-bool",
|
||||
\\enum SomeEnum { A, B, C };
|
||||
\\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
|
||||
@ -1764,7 +1759,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub export fn abs(arg_a: c_int) c_int {
|
||||
\\ var a = arg_a;
|
||||
\\ return if (a < 0) -a else a;
|
||||
\\ return if (a < @as(c_int, 0)) -a else a;
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -1845,7 +1840,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var i: c_int = 0;
|
||||
\\ var u: c_uint = @intCast(c_uint, 0);
|
||||
\\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
|
||||
\\ i += 1;
|
||||
\\ i -= 1;
|
||||
\\ u +%= 1;
|
||||
@ -1885,7 +1880,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export fn log2(arg_a: c_uint) c_int {
|
||||
\\ var a = arg_a;
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (a > @intCast(c_uint, 0)) {
|
||||
\\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
|
||||
\\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ }
|
||||
\\ return i;
|
||||
@ -1905,7 +1900,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub export fn log2(arg_a: u32) c_int {
|
||||
\\ var a = arg_a;
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (a > @intCast(c_uint, 0)) {
|
||||
\\ while (a > @bitCast(c_uint, @as(c_int, 0))) {
|
||||
\\ a >>= @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ }
|
||||
\\ return i;
|
||||
@ -1929,42 +1924,42 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ var a: c_int = 0;
|
||||
\\ a += (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* + 1;
|
||||
\\ ref.* = ref.* + @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a -= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* - 1;
|
||||
\\ ref.* = ref.* - @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a *= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* * 1;
|
||||
\\ ref.* = ref.* * @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a &= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* & 1;
|
||||
\\ ref.* = ref.* & @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a |= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* | 1;
|
||||
\\ ref.* = ref.* | @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a ^= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* ^ 1;
|
||||
\\ ref.* = ref.* ^ @as(c_int, 1);
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\ a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\}
|
||||
@ -1984,45 +1979,45 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var a: c_uint = @intCast(c_uint, 0);
|
||||
\\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0));
|
||||
\\ a +%= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* +% @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a -%= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* -% @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a *%= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* *% @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a &= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* & @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a |= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* | @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a ^= (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* ^ @intCast(c_uint, 1);
|
||||
\\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ });
|
||||
\\ a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ ref.* = ref.* >> @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\ a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
|
||||
\\ const ref = &a;
|
||||
\\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), 1);
|
||||
\\ ref.* = ref.* << @as(@import("std").math.Log2Int(c_int), @as(c_int, 1));
|
||||
\\ break :blk ref.*;
|
||||
\\ }));
|
||||
\\}
|
||||
@ -2044,7 +2039,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {
|
||||
\\ var i: c_int = 0;
|
||||
\\ var u: c_uint = @intCast(c_uint, 0);
|
||||
\\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
|
||||
\\ i += 1;
|
||||
\\ i -= 1;
|
||||
\\ u +%= 1;
|
||||
@ -2115,19 +2110,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ fn_int(@floatToInt(c_int, 3));
|
||||
\\ fn_int(@floatToInt(c_int, 3));
|
||||
\\ fn_int(@floatToInt(c_int, 3));
|
||||
\\ fn_int(1094861636);
|
||||
\\ fn_f32(@intToFloat(f32, 3));
|
||||
\\ fn_f64(@intToFloat(f64, 3));
|
||||
\\ fn_char(@intCast(u8, '3'));
|
||||
\\ fn_char(@intCast(u8, '\x01'));
|
||||
\\ fn_char(@intCast(u8, 0));
|
||||
\\ fn_int(@as(c_int, 1094861636));
|
||||
\\ fn_f32(@intToFloat(f32, @as(c_int, 3)));
|
||||
\\ fn_f64(@intToFloat(f64, @as(c_int, 3)));
|
||||
\\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '3'))));
|
||||
\\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, '\x01'))));
|
||||
\\ fn_char(@bitCast(u8, @truncate(i8, @as(c_int, 0))));
|
||||
\\ fn_f32(3);
|
||||
\\ fn_f64(3);
|
||||
\\ fn_bool(123 != 0);
|
||||
\\ fn_bool(0 != 0);
|
||||
\\ fn_bool(@as(c_int, 123) != 0);
|
||||
\\ fn_bool(@as(c_int, 0) != 0);
|
||||
\\ fn_bool(@ptrToInt(&fn_int) != 0);
|
||||
\\ fn_int(@intCast(c_int, @ptrToInt(&fn_int)));
|
||||
\\ fn_ptr(@intToPtr(?*c_void, 42));
|
||||
\\ fn_ptr(@intToPtr(?*c_void, @as(c_int, 42)));
|
||||
\\}
|
||||
});
|
||||
|
||||
@ -2223,8 +2218,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo() void {
|
||||
\\ if (1 != 0) while (true) {
|
||||
\\ if (!(0 != 0)) break;
|
||||
\\ if (@as(c_int, 1) != 0) while (true) {
|
||||
\\ if (!(@as(c_int, 0) != 0)) break;
|
||||
\\ };
|
||||
\\}
|
||||
});
|
||||
@ -2263,4 +2258,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ };
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("widening and truncating integer casting to different signedness",
|
||||
\\unsigned long foo(void) {
|
||||
\\ return -1;
|
||||
\\}
|
||||
\\unsigned short bar(long x) {
|
||||
\\ return x;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_ulong {
|
||||
\\ return @bitCast(c_ulong, @as(c_long, -@as(c_int, 1)));
|
||||
\\}
|
||||
\\pub export fn bar(arg_x: c_long) c_ushort {
|
||||
\\ var x = arg_x;
|
||||
\\ return @bitCast(c_ushort, @truncate(c_short, x));
|
||||
\\}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user