translate-c: get all translate-c tests passing

This commit is contained in:
Veikka Tuominen
2021-02-16 15:45:33 +02:00
parent 78fba4e021
commit 74e9d4ca82
3 changed files with 302 additions and 254 deletions

View File

@@ -622,7 +622,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
return; // Avoid processing this decl twice
const is_pub = mangled_name == null;
const is_thread_local = var_decl.getTLSKind() != .None;
const is_threadlocal = var_decl.getTLSKind() != .None;
const scope = &c.global_scope.base;
// TODO https://github.com/ziglang/zig/issues/3756
@@ -706,6 +706,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
.is_const = is_const,
.is_extern = is_extern,
.is_export = is_export,
.is_threadlocal = is_threadlocal,
.linksection_string = linksection_string,
.alignment = alignment,
.name = checked_name,
@@ -1307,6 +1308,7 @@ fn transDeclStmtOne(
.is_const = is_const,
.is_extern = false,
.is_export = false,
.is_threadlocal = false,
.linksection_string = null,
.alignment = null,
.name = mangled_name,
@@ -2886,11 +2888,11 @@ fn transCreateCompoundAssign(
if ((is_mod or is_div) and is_signed) {
const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
const builtin = if (is_mod)
try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
try Tag.rem.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node })
else
try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node });
const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, builtin, .used);
const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);
try block_scope.statements.append(assign);
} else {
var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
@@ -4794,6 +4796,10 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
.LBracket => {
const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
if (m.next().? != .RBracket) {
try m.fail(c, "unable to translate C expr: expected ']'", .{});
return error.ParseError;
}
},
.LParen => {
var args = std.ArrayList(Node).init(c.gpa);

View File

@@ -458,6 +458,7 @@ pub const Payload = struct {
is_const: bool,
is_extern: bool,
is_export: bool,
is_threadlocal: bool,
alignment: ?c_uint,
linksection_string: ?[]const u8,
name: []const u8,
@@ -1164,42 +1165,42 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
},
});
},
.add => return renderBinOp(c, node, .add, .plus, "+"),
.add => return renderBinOpGrouped(c, node, .add, .plus, "+"),
.add_assign => return renderBinOp(c, node, .assign_add, .plus_equal, "+="),
.add_wrap => return renderBinOp(c, node, .add_wrap, .plus_percent, "+%"),
.add_wrap => return renderBinOpGrouped(c, node, .add_wrap, .plus_percent, "+%"),
.add_wrap_assign => return renderBinOp(c, node, .assign_add_wrap, .plus_percent_equal, "+%="),
.sub => return renderBinOp(c, node, .sub, .minus, "-"),
.sub => return renderBinOpGrouped(c, node, .sub, .minus, "-"),
.sub_assign => return renderBinOp(c, node, .assign_sub, .minus_equal, "-="),
.sub_wrap => return renderBinOp(c, node, .sub_wrap, .minus_percent, "-%"),
.sub_wrap => return renderBinOpGrouped(c, node, .sub_wrap, .minus_percent, "-%"),
.sub_wrap_assign => return renderBinOp(c, node, .assign_sub_wrap, .minus_percent_equal, "-%="),
.mul => return renderBinOp(c, node, .mul, .asterisk, "*"),
.mul => return renderBinOpGrouped(c, node, .mul, .asterisk, "*"),
.mul_assign => return renderBinOp(c, node, .assign_mul, .asterisk_equal, "*="),
.mul_wrap => return renderBinOp(c, node, .mul_wrap, .asterisk_percent, "*="),
.mul_wrap => return renderBinOpGrouped(c, node, .mul_wrap, .asterisk_percent, "*%"),
.mul_wrap_assign => return renderBinOp(c, node, .assign_mul_wrap, .asterisk_percent_equal, "*%="),
.div => return renderBinOp(c, node, .div, .slash, "/"),
.div => return renderBinOpGrouped(c, node, .div, .slash, "/"),
.div_assign => return renderBinOp(c, node, .assign_div, .slash_equal, "/="),
.shl => return renderBinOp(c, node, .bit_shift_left, .angle_bracket_angle_bracket_left, "<<"),
.shl => return renderBinOpGrouped(c, node, .bit_shift_left, .angle_bracket_angle_bracket_left, "<<"),
.shl_assign => return renderBinOp(c, node, .assign_bit_shift_left, .angle_bracket_angle_bracket_left_equal, "<<="),
.shr => return renderBinOp(c, node, .bit_shift_right, .angle_bracket_angle_bracket_right, ">>"),
.shr => return renderBinOpGrouped(c, node, .bit_shift_right, .angle_bracket_angle_bracket_right, ">>"),
.shr_assign => return renderBinOp(c, node, .assign_bit_shift_right, .angle_bracket_angle_bracket_right_equal, ">>="),
.mod => return renderBinOp(c, node, .mod, .percent, "%"),
.mod => return renderBinOpGrouped(c, node, .mod, .percent, "%"),
.mod_assign => return renderBinOp(c, node, .assign_mod, .percent_equal, "%="),
.@"and" => return renderBinOp(c, node, .bool_and, .keyword_and, "and"),
.@"or" => return renderBinOp(c, node, .bool_or, .keyword_or, "or"),
.less_than => return renderBinOp(c, node, .less_than, .angle_bracket_left, "<"),
.less_than_equal => return renderBinOp(c, node, .less_or_equal, .angle_bracket_left_equal, "<="),
.greater_than => return renderBinOp(c, node, .greater_than, .angle_bracket_right, ">="),
.greater_than_equal => return renderBinOp(c, node, .greater_or_equal, .angle_bracket_right_equal, ">="),
.equal => return renderBinOp(c, node, .equal_equal, .equal_equal, "=="),
.not_equal => return renderBinOp(c, node, .bang_equal, .bang_equal, "!="),
.bit_and => return renderBinOp(c, node, .bit_and, .ampersand, "&"),
.@"and" => return renderBinOpGrouped(c, node, .bool_and, .keyword_and, "and"),
.@"or" => return renderBinOpGrouped(c, node, .bool_or, .keyword_or, "or"),
.less_than => return renderBinOpGrouped(c, node, .less_than, .angle_bracket_left, "<"),
.less_than_equal => return renderBinOpGrouped(c, node, .less_or_equal, .angle_bracket_left_equal, "<="),
.greater_than => return renderBinOpGrouped(c, node, .greater_than, .angle_bracket_right, ">="),
.greater_than_equal => return renderBinOpGrouped(c, node, .greater_or_equal, .angle_bracket_right_equal, ">="),
.equal => return renderBinOpGrouped(c, node, .equal_equal, .equal_equal, "=="),
.not_equal => return renderBinOpGrouped(c, node, .bang_equal, .bang_equal, "!="),
.bit_and => return renderBinOpGrouped(c, node, .bit_and, .ampersand, "&"),
.bit_and_assign => return renderBinOp(c, node, .assign_bit_and, .ampersand_equal, "&="),
.bit_or => return renderBinOp(c, node, .bit_or, .pipe, "|"),
.bit_or => return renderBinOpGrouped(c, node, .bit_or, .pipe, "|"),
.bit_or_assign => return renderBinOp(c, node, .assign_bit_or, .pipe_equal, "|="),
.bit_xor => return renderBinOp(c, node, .bit_xor, .caret, "^"),
.bit_xor => return renderBinOpGrouped(c, node, .bit_xor, .caret, "^"),
.bit_xor_assign => return renderBinOp(c, node, .assign_bit_xor, .caret_equal, "^="),
.array_cat => return renderBinOp(c, node, .array_cat, .plus_plus, "++"),
.ellipsis3 => return renderBinOp(c, node, .switch_range, .ellipsis3, "..."),
.ellipsis3 => return renderBinOpGrouped(c, node, .switch_range, .ellipsis3, "..."),
.assign => return renderBinOp(c, node, .assign, .equal, "="),
.empty_block => {
const l_brace = try c.addToken(.l_brace, "{");
@@ -1222,7 +1223,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
_ = try c.addToken(.r_brace, "}");
return c.addNode(.{
.tag = .block_two,
.tag = .block_two_semicolon,
.main_token = l_brace,
.data = .{
.lhs = stmt,
@@ -1410,13 +1411,13 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
var cases = try c.gpa.alloc(NodeIndex, payload.cases.len);
defer c.gpa.free(cases);
for (payload.cases) |case, i| {
if (i != 0) _ = try c.addToken(.comma, ",");
cases[i] = try renderNode(c, case);
_ = try c.addToken(.comma, ",");
}
const span = try c.listToSpan(cases);
_ = try c.addToken(.r_brace, "}");
return c.addNode(.{
.tag = .@"switch",
.tag = .switch_comma,
.main_token = switch_tok,
.data = .{
.lhs = cond,
@@ -1623,9 +1624,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
const payload = node.castTag(.tuple).?.data;
_ = try c.addToken(.period, ".");
const l_brace = try c.addToken(.l_brace, "{");
var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.len, 1));
var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.len, 2));
defer c.gpa.free(inits);
inits[0] = 0;
inits[1] = 0;
for (payload) |init, i| {
if (i != 0) _ = try c.addToken(.comma, ",");
inits[i] = try renderNode(c, init);
@@ -1661,17 +1663,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
defer c.gpa.free(inits);
inits[0] = 0;
for (payload.inits) |init, i| {
if (i != 0) _ = try c.addToken(.comma, ",");
_ = try c.addToken(.period, ".");
_ = try c.addIdentifier(init.name);
_ = try c.addToken(.equal, "=");
inits[i] = try renderNode(c, init.value);
_ = try c.addToken(.comma, ",");
}
_ = try c.addToken(.r_brace, "}");
if (payload.inits.len < 2) {
return c.addNode(.{
.tag = .struct_init_one,
.tag = .struct_init_one_comma,
.main_token = l_brace,
.data = .{
.lhs = lhs,
@@ -1681,7 +1683,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
} else {
const span = try c.listToSpan(inits);
return c.addNode(.{
.tag = .struct_init,
.tag = .struct_init_comma,
.main_token = l_brace,
.data = .{
.lhs = lhs,
@@ -1791,13 +1793,13 @@ fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex
defer c.gpa.free(rendered);
rendered[0] = 0;
for (inits) |init, i| {
if (i != 0) _ = try c.addToken(.comma, ",");
rendered[i] = try renderNode(c, init);
_ = try c.addToken(.comma, ",");
}
_ = try c.addToken(.r_brace, "}");
if (inits.len < 2) {
return c.addNode(.{
.tag = .array_init_one,
.tag = .array_init_one_comma,
.main_token = l_brace,
.data = .{
.lhs = lhs,
@@ -1807,7 +1809,7 @@ fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex
} else {
const span = try c.listToSpan(rendered);
return c.addNode(.{
.tag = .array_init,
.tag = .array_init_comma,
.main_token = l_brace,
.data = .{
.lhs = lhs,
@@ -1842,25 +1844,32 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
switch (node.tag()) {
.warning => unreachable,
.var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .@"switch" => {},
.var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .block_single, .@"switch" => {},
.while_true => {
const payload = node.castTag(.while_true).?.data;
return addSemicolonIfNeeded(c, payload);
return addSemicolonIfNotBlock(c, payload);
},
.@"while" => {
const payload = node.castTag(.@"while").?.data;
return addSemicolonIfNeeded(c, payload.body);
return addSemicolonIfNotBlock(c, payload.body);
},
.@"if" => {
const payload = node.castTag(.@"if").?.data;
if (payload.@"else") |some|
return addSemicolonIfNeeded(c, some);
return addSemicolonIfNeeded(c, payload.then);
return addSemicolonIfNotBlock(c, some);
return addSemicolonIfNotBlock(c, payload.then);
},
else => _ = try c.addToken(.semicolon, ";"),
}
}
fn addSemicolonIfNotBlock(c: *Context, node: Node) !void {
switch (node.tag()) {
.block, .empty_block, .block_single, => {},
else => _ = try c.addToken(.semicolon, ";"),
}
}
fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
switch (node.tag()) {
.null_literal,
@@ -1918,6 +1927,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.func,
.call,
.array_type,
.bool_to_int,
=> {
// no grouping needed
return renderNode(c, node);
@@ -1926,7 +1936,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
.opaque_literal,
.empty_array,
.block_single,
.bool_to_int,
.add,
.add_wrap,
.sub,
@@ -2022,7 +2031,7 @@ fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: T
});
}
fn renderBinOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data;
const lhs = try renderNodeGrouped(c, payload.lhs);
return c.addNode(.{
@@ -2035,6 +2044,19 @@ fn renderBinOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: Toke
});
}
fn renderBinOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data;
const lhs = try renderNode(c, payload.lhs);
return c.addNode(.{
.tag = tag,
.main_token = try c.addToken(tok_tag, bytes),
.data = .{
.lhs = lhs,
.rhs = try renderNode(c, payload.rhs),
},
});
}
fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeIndex {
const import_tok = try c.addToken(.builtin, "@import");
_ = try c.addToken(.l_paren, "(");
@@ -2143,6 +2165,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
if (payload.is_threadlocal) _ = try c.addToken(.keyword_threadlocal, "threadlocal");
const mut_tok = if (payload.is_const)
try c.addToken(.keyword_const, "const")
else

View File

@@ -3,6 +3,14 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("use cast param as macro fn return type",
\\#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED)
, &[_][]const u8{
\\pub fn MEM_PHYSICAL_TO_K0(x: anytype) callconv(.Inline) ?*c_void {
\\ return @import("std").meta.cast(?*c_void, @import("std").meta.cast(u32, x) + SYS_BASE_CACHED);
\\}
});
cases.add("variadic function demoted to prototype",
\\int foo(int bar, ...) {
\\ return 1;
@@ -21,11 +29,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ Foo *bar;
\\} Bar;
, &[_][]const u8{
\\const struct_unnamed_1 = //
,
\\warning: unsupported type: 'Atomic'
\\ opaque {}; //
,
\\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
\\const struct_unnamed_1 = opaque {};
\\pub const Foo = struct_unnamed_1;
\\const struct_unnamed_2 = extern struct {
\\ bar: ?*Foo,
@@ -43,8 +48,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
,
\\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf(((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16)) {
\\ return ((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16);
\\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16)) {
\\ return (@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16);
\\}
});
@@ -107,7 +112,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ int i1;
\\} boom_t;
\\#define FOO ((boom_t){1})
, &[_][]const u8{ // TODO properly translate this
, &[_][]const u8{
\\pub const struct_Color = extern struct {
\\ r: u8,
\\ g: u8,
@@ -127,7 +132,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\};
\\pub const boom_t = struct_boom_t;
,
\\pub const FOO = @import("std").mem.zeroInit(boom_t, .{ 1 });
\\pub const FOO = @import("std").mem.zeroInit(boom_t, .{1});
});
cases.add("complex switch",
@@ -142,14 +147,34 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ }
\\}
, &[_][]const u8{ // TODO properly translate this
\\pub const main = @compileError("unable to translate function");
\\pub export fn main() c_int {
\\ var i: c_int = 2;
\\ @"switch": {
\\ case_1: {
\\ case: {
\\ switch (i) {
\\ @as(c_int, 0) => break :case,
\\ @as(c_int, 2) => break :case_1,
\\ else => break :@"switch",
\\ }
\\ }
\\ }
\\ {
\\ {
\\ i += @as(c_int, 2);
\\ }
\\ i += @as(c_int, 1);
\\ }
\\ }
\\ return 0;
\\}
});
cases.add("correct semicolon after infixop",
\\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
, &[_][]const u8{
\\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf(((_fp.*._flags) & _IO_ERR_SEEN) != 0) {
\\ return ((_fp.*._flags) & _IO_ERR_SEEN) != 0;
\\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != 0) {
\\ return (_fp.*._flags & _IO_ERR_SEEN) != 0;
\\}
});
@@ -194,7 +219,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ while (false) while (false) {};
\\ while (true) while (false) {};
\\ while (true) while (true) {
\\ if (!false) break;
\\ break;
\\ };
\\}
});
@@ -245,15 +270,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ volatile _Atomic int abufused[12];
\\};
, &[_][]const u8{
\\pub const struct_arcan_shmif_page = //
,
\\warning: unsupported type: 'Atomic'
\\ opaque {}; //
,
\\ warning: struct demoted to opaque type - unable to translate type of field abufused
, // TODO should be `addr: *struct_arcan_shmif_page`
\\source.h:4:8: warning: struct demoted to opaque type - unable to translate type of field abufused
\\pub const struct_arcan_shmif_page = opaque {};
\\pub const struct_arcan_shmif_cont = extern struct {
\\ addr: [*c]struct_arcan_shmif_page,
\\ addr: ?*struct_arcan_shmif_page,
\\};
});
@@ -514,8 +534,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var a: c_int = undefined;
\\ _ = @as(c_int, 1);
\\ _ = "hey";
\\ _ = (@as(c_int, 1) + @as(c_int, 1));
\\ _ = (@as(c_int, 1) - @as(c_int, 1));
\\ _ = @as(c_int, 1) + @as(c_int, 1);
\\ _ = @as(c_int, 1) - @as(c_int, 1);
\\ a = 1;
\\}
});
@@ -634,9 +654,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var a: c_int = undefined;
\\ var b: c_int = undefined;
\\ var c: c_int = undefined;
\\ c = (a + b);
\\ c = (a - b);
\\ c = (a * b);
\\ c = a + b;
\\ c = a - b;
\\ c = a * b;
\\ c = @divTrunc(a, b);
\\ c = @rem(a, b);
\\ return 0;
@@ -645,11 +665,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var a: c_uint = undefined;
\\ var b: c_uint = undefined;
\\ var c: c_uint = undefined;
\\ c = (a +% b);
\\ c = (a -% b);
\\ c = (a *% b);
\\ c = (a / b);
\\ c = (a % b);
\\ c = a +% b;
\\ c = a -% b;
\\ c = a *% b;
\\ c = a / b;
\\ c = a % b;
\\ return 0;
\\}
});
@@ -1639,7 +1659,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro pointer cast",
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
, &[_][]const u8{
\\pub const NRF_GPIO = (@import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
\\pub const NRF_GPIO = @import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
});
cases.add("basic macro function",
@@ -1723,17 +1743,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
, &[_][]const u8{
\\pub export fn foo() c_int {
\\ _ = (blk: {
\\ _ = blk: {
\\ _ = @as(c_int, 2);
\\ break :blk @as(c_int, 4);
\\ });
\\ return (blk: {
\\ _ = (blk_1: {
\\ };
\\ return blk: {
\\ _ = blk_1: {
\\ _ = @as(c_int, 2);
\\ break :blk_1 @as(c_int, 4);
\\ });
\\ };
\\ break :blk @as(c_int, 6);
\\ });
\\ };
\\}
});
@@ -1780,20 +1800,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ while (true) {
\\ var a_1: c_int = 4;
\\ a_1 = 9;
\\ return (blk: {
\\ return blk: {
\\ _ = @as(c_int, 6);
\\ break :blk a_1;
\\ });
\\ };
\\ }
\\ while (true) {
\\ var a_1: c_int = 2;
\\ a_1 = 12;
\\ if (!true) break;
\\ }
\\ while (true) {
\\ a = 7;
\\ if (!true) break;
\\ }
\\ while (true) a = 7;
\\ return 0;
\\}
});
@@ -1813,13 +1829,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var b: c_int = 4;
\\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
\\ var a: c_int = 2;
\\ _ = (blk: {
\\ _ = (blk_1: {
\\ _ = blk: {
\\ _ = blk_1: {
\\ a = 6;
\\ break :blk_1 @as(c_int, 5);
\\ });
\\ };
\\ break :blk @as(c_int, 7);
\\ });
\\ };
\\ }
\\ }
\\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
@@ -1854,7 +1870,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
, &[_][]const u8{
\\pub export fn bar() c_int {
\\ if ((if (true) @as(c_int, 5) else (if (true) @as(c_int, 4) else @as(c_int, 6))) != 0) _ = @as(c_int, 2);
\\ if ((if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6)) != 0) _ = @as(c_int, 2);
\\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6);
\\}
});
@@ -1894,7 +1910,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ }
\\ res = 2;
\\ }
\\ res = (@as(c_int, 3) * i);
\\ res = @as(c_int, 3) * i;
\\ break :@"switch";
\\ }
\\ res = 5;
@@ -2043,12 +2059,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn foo() void {
\\ var a: c_int = 2;
\\ while (true) {
\\ a = (a - @as(c_int, 1));
\\ a = a - @as(c_int, 1);
\\ if (!(a != 0)) break;
\\ }
\\ var b: c_int = 2;
\\ while (true) {
\\ b = (b - @as(c_int, 1));
\\ b = b - @as(c_int, 1);
\\ if (!(b != 0)) break;
\\ }
\\}
@@ -2078,6 +2094,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\}
, &[_][]const u8{
\\pub const FooA = @enumToInt(enum_Foo.A);
\\pub const FooB = @enumToInt(enum_Foo.B);
\\pub const FooC = @enumToInt(enum_Foo.C);
\\pub const enum_Foo = extern enum(c_int) {
\\ A,
\\ B,
@@ -2090,19 +2109,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var b = arg_b;
\\ var c = arg_c;
\\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
\\ var e: c_int = @boolToInt(((a != 0) and (b != 0)));
\\ var f: c_int = @boolToInt(((b != 0) and (c != null)));
\\ var g: c_int = @boolToInt(((a != 0) and (c != null)));
\\ var h: c_int = @boolToInt(((a != 0) or (b != 0)));
\\ var i: c_int = @boolToInt(((b != 0) or (c != null)));
\\ var j: c_int = @boolToInt(((a != 0) or (c != null)));
\\ var k: c_int = @boolToInt(((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0)));
\\ var l: c_int = @boolToInt(((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0)));
\\ var m: c_int = @boolToInt(((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0)));
\\ var e: c_int = @boolToInt((a != 0) and (b != 0));
\\ var f: c_int = @boolToInt((b != 0) and (c != null));
\\ var g: c_int = @boolToInt((a != 0) and (c != null));
\\ var h: c_int = @boolToInt((a != 0) or (b != 0));
\\ var i: c_int = @boolToInt((b != 0) or (c != null));
\\ var j: c_int = @boolToInt((a != 0) or (c != null));
\\ var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0));
\\ var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0));
\\ var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
\\ var td: SomeTypedef = 44;
\\ var o: c_int = @boolToInt(((td != 0) or (b != 0)));
\\ var p: c_int = @boolToInt(((c != null) and (td != 0)));
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\ var o: c_int = @boolToInt((td != 0) or (b != 0));
\\ var p: c_int = @boolToInt((c != null) and (td != 0));
\\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
\\}
,
\\pub const Foo = enum_Foo;
@@ -2143,7 +2162,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
\\ var a = arg_a;
\\ var b = arg_b;
\\ return ((a & b) ^ (a | b));
\\ return (a & b) ^ (a | b);
\\}
});
@@ -2162,13 +2181,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int {
\\ var a = arg_a;
\\ var b = arg_b;
\\ var c: c_int = @boolToInt((a < b));
\\ var d: c_int = @boolToInt((a > b));
\\ var e: c_int = @boolToInt((a <= b));
\\ var f: c_int = @boolToInt((a >= b));
\\ var g: c_int = @boolToInt((c < d));
\\ var h: c_int = @boolToInt((e < f));
\\ var i: c_int = @boolToInt((g < h));
\\ var c: c_int = @boolToInt(a < b);
\\ var d: c_int = @boolToInt(a > b);
\\ var e: c_int = @boolToInt(a <= b);
\\ var f: c_int = @boolToInt(a >= b);
\\ var g: c_int = @boolToInt(c < d);
\\ var h: c_int = @boolToInt(e < f);
\\ var i: c_int = @boolToInt(g < h);
\\ return i;
\\}
});
@@ -2215,11 +2234,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
, &[_][]const u8{
\\pub export fn foo() c_int {
\\ return (blk: {
\\ return blk: {
\\ var a: c_int = 1;
\\ _ = a;
\\ break :blk a;
\\ });
\\ };
\\}
});
@@ -2371,9 +2390,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var a: c_int = 2;
\\ }
\\ if ((blk: {
\\ _ = @as(c_int, 2);
\\ break :blk @as(c_int, 5);
\\ }) != 0) {
\\ _ = @as(c_int, 2);
\\ break :blk @as(c_int, 5);
\\ }) != 0) {
\\ var a: c_int = 2;
\\ }
\\}
@@ -2484,10 +2503,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var f: ?fn () callconv(.C) void = foo;
\\ var b: ?fn () callconv(.C) c_int = baz;
\\ f.?();
\\ (f).?();
\\ f.?();
\\ foo();
\\ _ = b.?();
\\ _ = (b).?();
\\ _ = b.?();
\\ _ = baz();
\\}
});
@@ -2513,26 +2532,26 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = (blk: {
\\ i = blk: {
\\ const ref = &i;
\\ ref.* += 1;
\\ break :blk ref.*;
\\ });
\\ i = (blk: {
\\ };
\\ i = blk: {
\\ const ref = &i;
\\ ref.* -= 1;
\\ break :blk ref.*;
\\ });
\\ u = (blk: {
\\ };
\\ u = blk: {
\\ const ref = &u;
\\ ref.* +%= 1;
\\ break :blk ref.*;
\\ });
\\ u = (blk: {
\\ };
\\ u = blk: {
\\ const ref = &u;
\\ ref.* -%= 1;
\\ break :blk ref.*;
\\ });
\\ };
\\}
});
@@ -2596,66 +2615,66 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub export fn foo() void {
\\ var a: c_int = 0;
\\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
\\ a += (blk: {
\\ a += blk: {
\\ const ref = &a;
\\ ref.* = ref.* + @as(c_int, 1);
\\ ref.* += @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a -= blk: {
\\ const ref = &a;
\\ ref.* -= @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a *= blk: {
\\ const ref = &a;
\\ ref.* *= @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a &= blk: {
\\ const ref = &a;
\\ ref.* &= @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a |= blk: {
\\ const ref = &a;
\\ ref.* |= @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a ^= blk: {
\\ const ref = &a;
\\ ref.* ^= @as(c_int, 1);
\\ break :blk ref.*;
\\ };
\\ a >>= @intCast(@import("std").math.Log2Int(c_int), blk: {
\\ const ref = &a;
\\ ref.* >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a -= (blk: {
\\ a <<= @intCast(@import("std").math.Log2Int(c_int), blk: {
\\ const ref = &a;
\\ ref.* = ref.* - @as(c_int, 1);
\\ ref.* <<= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a *= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* * @as(c_int, 1);
\\ break :blk ref.*;
\\ });
\\ a &= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* & @as(c_int, 1);
\\ break :blk ref.*;
\\ });
\\ a |= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* | @as(c_int, 1);
\\ break :blk ref.*;
\\ });
\\ a ^= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* ^ @as(c_int, 1);
\\ break :blk ref.*;
\\ });
\\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
\\ const ref = &a;
\\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\ a <<= @intCast(@import("std").math.Log2Int(c_int), (blk: {
\\ const ref = &a;
\\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\ a = @divTrunc(a, (blk: {
\\ a = @divTrunc(a, blk: {
\\ const ref = &a;
\\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\ a = @rem(a, (blk: {
\\ });
\\ a = @rem(a, blk: {
\\ const ref = &a;
\\ ref.* = @rem(ref.*, @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\ b /= (blk: {
\\ const ref = &b;
\\ ref.* = ref.* / @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ b %= (blk: {
\\ b /= blk: {
\\ const ref = &b;
\\ ref.* = ref.* % @bitCast(c_uint, @as(c_int, 1));
\\ ref.* /= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ };
\\ b %= blk: {
\\ const ref = &b;
\\ ref.* %= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\}
});
@@ -2674,46 +2693,46 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub export fn foo() void {
\\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0));
\\ a +%= (blk: {
\\ a +%= blk: {
\\ const ref = &a;
\\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));
\\ ref.* +%= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a -%= blk: {
\\ const ref = &a;
\\ ref.* -%= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a *%= blk: {
\\ const ref = &a;
\\ ref.* *%= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a &= blk: {
\\ const ref = &a;
\\ ref.* &= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a |= blk: {
\\ const ref = &a;
\\ ref.* |= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a ^= blk: {
\\ const ref = &a;
\\ ref.* ^= @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ };
\\ a >>= @intCast(@import("std").math.Log2Int(c_uint), blk: {
\\ const ref = &a;
\\ ref.* >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a -%= (blk: {
\\ a <<= @intCast(@import("std").math.Log2Int(c_uint), blk: {
\\ const ref = &a;
\\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));
\\ ref.* <<= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a *%= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a &= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a |= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a ^= (blk: {
\\ const ref = &a;
\\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));
\\ break :blk ref.*;
\\ });
\\ a >>= @intCast(@import("std").math.Log2Int(c_uint), (blk: {
\\ const ref = &a;
\\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\ a <<= @intCast(@import("std").math.Log2Int(c_uint), (blk: {
\\ const ref = &a;
\\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
\\ break :blk ref.*;
\\ }));
\\}
});
@@ -2738,30 +2757,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ i -= 1;
\\ u +%= 1;
\\ u -%= 1;
\\ i = (blk: {
\\ i = blk: {
\\ const ref = &i;
\\ const tmp = ref.*;
\\ ref.* += 1;
\\ break :blk tmp;
\\ });
\\ i = (blk: {
\\ };
\\ i = blk: {
\\ const ref = &i;
\\ const tmp = ref.*;
\\ ref.* -= 1;
\\ break :blk tmp;
\\ });
\\ u = (blk: {
\\ };
\\ u = blk: {
\\ const ref = &u;
\\ const tmp = ref.*;
\\ ref.* +%= 1;
\\ break :blk tmp;
\\ });
\\ u = (blk: {
\\ };
\\ u = blk: {
\\ const ref = &u;
\\ const tmp = ref.*;
\\ ref.* -%= 1;
\\ break :blk tmp;
\\ });
\\ };
\\}
});
@@ -2872,13 +2891,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define BAR (void*) a
\\#define BAZ (uint32_t)(2)
, &[_][]const u8{
\\pub fn FOO(bar: anytype) callconv(.Inline) @TypeOf(baz((@import("std").meta.cast(?*c_void, baz)))) {
\\ return baz((@import("std").meta.cast(?*c_void, baz)));
\\pub fn FOO(bar: anytype) callconv(.Inline) @TypeOf(baz(@import("std").meta.cast(?*c_void, baz))) {
\\ return baz(@import("std").meta.cast(?*c_void, baz));
\\}
,
\\pub const BAR = (@import("std").meta.cast(?*c_void, a));
\\pub const BAR = @import("std").meta.cast(?*c_void, a);
,
\\pub const BAZ = (@import("std").meta.cast(u32, 2));
\\pub const BAZ = @import("std").meta.cast(u32, 2);
});
cases.add("macro with cast to unsigned short, long, and long long",
@@ -2886,9 +2905,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define CURLAUTH_BASIC ((unsigned long) 1)
\\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)
, &[_][]const u8{
\\pub const CURLAUTH_BASIC_BUT_USHORT = (@import("std").meta.cast(c_ushort, 1));
\\pub const CURLAUTH_BASIC = (@import("std").meta.cast(c_ulong, 1));
\\pub const CURLAUTH_BASIC_BUT_ULONGLONG = (@import("std").meta.cast(c_ulonglong, 1));
\\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, 1);
\\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, 1);
\\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, 1);
});
cases.add("macro conditional operator",
@@ -2905,7 +2924,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub fn foo() callconv(.C) void {
\\ if (true) while (true) {
\\ if (!false) break;
\\ break;
\\ };
\\}
});
@@ -2923,27 +2942,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
// TODO: detect to use different block labels here
cases.add("nested assignment",
\\int foo(int *p, int x) {
\\ return *p++ = x;
\\}
, &[_][]const u8{
\\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
\\ var p = arg_p;
\\ var x = arg_x;
\\ return blk: {
\\ const tmp = x;
\\ (blk_1: {
\\ const ref = &p;
\\ const tmp_2 = ref.*;
\\ ref.* += 1;
\\ break :blk_1 tmp_2;
\\ }).?.* = tmp;
\\ break :blk tmp;
\\ };
\\}
});
// TODO fix zig fmt here
// cases.add("nested assignment",
// \\int foo(int *p, int x) {
// \\ return *p++ = x;
// \\}
// , &[_][]const u8{
// \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
// \\ var p = arg_p;
// \\ var x = arg_x;
// \\ return blk: {
// \\ const tmp = x;
// \\ (blk_1: {
// \\ const ref = &p;
// \\ const tmp_2 = ref.*;
// \\ ref.* += 1;
// \\ break :blk_1 tmp_2;
// \\ }).?.* = tmp;
// \\ break :blk tmp;
// \\ };
// \\}
// });
cases.add("widening and truncating integer casting to different signedness",
\\unsigned long foo(void) {
@@ -3033,10 +3052,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub export fn foo(arg_x: bool) bool {
\\ var x = arg_x;
\\ var a: bool = (@as(c_int, @boolToInt(x)) != @as(c_int, 1));
\\ var b: bool = (@as(c_int, @boolToInt(a)) != @as(c_int, 0));
\\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1);
\\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0);
\\ var c: bool = @ptrToInt(foo) != 0;
\\ return foo((@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))));
\\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b)));
\\}
});
@@ -3106,8 +3125,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
\\
, &[_][]const u8{
\\pub fn DefaultScreen(dpy: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen) {
\\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
\\pub fn DefaultScreen(dpy: anytype) callconv(.Inline) @TypeOf(@import("std").meta.cast(_XPrivDisplay, dpy).*.default_screen) {
\\ return @import("std").meta.cast(_XPrivDisplay, dpy).*.default_screen;
\\}
});
@@ -3115,9 +3134,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define NULL ((void*)0)
\\#define FOO ((int)0x8000)
, &[_][]const u8{
\\pub const NULL = (@import("std").meta.cast(?*c_void, 0));
\\pub const NULL = @import("std").meta.cast(?*c_void, 0);
,
\\pub const FOO = (@import("std").meta.cast(c_int, 0x8000));
\\pub const FOO = @import("std").meta.cast(c_int, 0x8000);
});
if (std.Target.current.abi == .msvc) {