diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 2eef92a201..f1249afa97 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -582,7 +582,9 @@ pub fn formatAsciiChar( comptime Errors: type, output: fn (@TypeOf(context), []const u8) Errors!void, ) Errors!void { - return output(context, @as(*const [1]u8, &c)[0..]); + if (std.ascii.isPrint(c)) + return output(context, @as(*const [1]u8, &c)[0..]); + return format(context, Errors, output, "\\x{x:0<2}", .{c}); } pub fn formatBuf( diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index b44f3a2389..efb3eb611f 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -78,6 +78,7 @@ pub const struct_ZigClangInitListExpr = @OpaqueType(); pub const ZigClangPreprocessingRecord = @OpaqueType(); pub const ZigClangFloatingLiteral = @OpaqueType(); pub const ZigClangConstantExpr = @OpaqueType(); +pub const ZigClangCharacterLiteral = @OpaqueType(); pub const ZigClangBO = extern enum { PtrMemD, @@ -712,6 +713,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum { UTF32, }; +pub const ZigClangCharacterLiteral_CharacterKind = extern enum { + Ascii, + Wide, + UTF8, + UTF16, + UTF32, +}; + pub const ZigClangRecordDecl_field_iterator = extern struct { opaque: *c_void, }; @@ -1077,3 +1086,7 @@ pub extern fn ZigClangExpr_EvaluateAsConstantExpr(*const ZigClangExpr, *ZigClang pub extern fn ZigClangPredefinedExpr_getFunctionName(*const ZigClangPredefinedExpr) *const ZigClangStringLiteral; +pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiteral) ZigClangSourceLocation; +pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind; +pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint; + diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 0933b7aa20..b3e32e4c45 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -49,7 +49,10 @@ const Scope = struct { Root, Condition, FnDef, + + /// used when getting a member `a.b` Ref, + Loop, }; const Switch = struct { @@ -59,11 +62,6 @@ const Scope = struct { has_default: bool = false, }; - /// used when getting a member `a.b` - const Ref = struct { - base: Scope, - }; - const Block = struct { base: Scope, block_node: *ast.Node.Block, @@ -125,10 +123,6 @@ const Scope = struct { } }; - const Condition = struct { - base: Scope, - }; - const FnDef = struct { base: Scope, params: AliasList, @@ -169,7 +163,6 @@ const Scope = struct { .Root => unreachable, .Block => return @fieldParentPtr(Block, "base", scope), .Condition => { - const cond = @fieldParentPtr(Condition, "base", scope); // comma operator used return try Block.init(c, scope, "blk"); }, @@ -192,6 +185,7 @@ const Scope = struct { .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name), .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), .Switch, + .Loop, .Condition => scope.parent.?.getAlias(name), }; } @@ -203,6 +197,7 @@ const Scope = struct { .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name), .Block => @fieldParentPtr(Block, "base", scope).contains(name), .Switch, + .Loop, .Condition => scope.parent.?.contains(name), }; } @@ -213,6 +208,7 @@ const Scope = struct { switch (scope.id) { .FnDef => unreachable, .Switch => return scope, + .Loop => return scope, else => scope = scope.parent.?, } } @@ -434,7 +430,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { error.OutOfMemory => |e| return e, }; }, - else => unreachable, + else => return failDecl(c, fn_decl_loc, fn_name, "unable to resolve function type {}", .{ZigClangType_getTypeClass(fn_type)}), }; if (!decl_ctx.has_body) { @@ -862,6 +858,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), else => { return revertAndWarn( rp, @@ -1202,7 +1199,7 @@ fn transStringLiteral( const token = try appendToken(rp.c, .StringLiteral, buf); const node = try rp.c.a().create(ast.Node.StringLiteral); - node.* = ast.Node.StringLiteral{ + node.* = .{ .token = token, }; return maybeSuppressResult(rp, scope, result_used, &node.base); @@ -1237,18 +1234,15 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { // Returns either a string literal or a slice of `buf`. fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { - // TODO: https://github.com/ziglang/zig/issues/2749 - const escaped = switch (c) { - // Printable ASCII except for ' " \ - ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..], - '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..], - '\n' => return "\\n"[0..], - '\r' => return "\\r"[0..], - '\t' => return "\\t"[0..], - else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable, + return switch (c) { + '\"' => "\\\""[0..], + '\'' => "\\'"[0..], + '\\' => "\\\\"[0..], + '\n' => "\\n"[0..], + '\r' => "\\r"[0..], + '\t' => "\\t"[0..], + else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable, }; - std.mem.copy(u8, char_buf, escaped); - return char_buf[0..escaped.len]; } fn transCCast( @@ -1459,13 +1453,11 @@ fn transIfStmt( // if (c) t else e const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope.Condition{ - .base = .{ - .parent = scope, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; - if_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); + if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); @@ -1485,16 +1477,18 @@ fn transWhileLoop( ) TransError!*ast.Node { const while_node = try transCreateNodeWhile(rp.c); - var cond_scope = Scope.Condition{ - .base = .{ - .parent = scope, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; - while_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); + while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); - while_node.body = try transStmt(rp, scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value); + var loop_scope = Scope{ + .parent = scope, + .id = .Loop, + }; + while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value); return &while_node.base; } @@ -1508,6 +1502,10 @@ fn transDoWhileLoop( while_node.condition = try transCreateNodeBoolLiteral(rp.c, true); _ = try appendToken(rp.c, .RParen, ")"); var new = false; + var loop_scope = Scope{ + .parent = scope, + .id = .Loop, + }; const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: { // there's already a block in C, so we'll append our condition to it. @@ -1520,7 +1518,7 @@ fn transDoWhileLoop( // zig: b; // zig: if (!cond) break; // zig: } - break :blk (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; + break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; } else blk: { // the C statement is without a block, so we need to create a block to contain it. // c: do @@ -1532,20 +1530,18 @@ fn transDoWhileLoop( // zig: } new = true; const block = try transCreateNodeBlock(rp.c, null); - try block.statements.push(try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); + try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); break :blk block; }; // if (!cond) break; const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope.Condition{ - .base = .{ - .parent = scope, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); - prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, false); + prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); _ = try appendToken(rp.c, .RParen, ")"); if_node.condition = &prefix_op.base; if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; @@ -1563,25 +1559,26 @@ fn transForLoop( scope: *Scope, stmt: *const ZigClangForStmt, ) TransError!*ast.Node { - var inner = scope; + var loop_scope = Scope{ + .parent = scope, + .id = .Loop, + }; var block = false; var block_scope: ?*Scope.Block = null; if (ZigClangForStmt_getInit(stmt)) |init| { block_scope = try Scope.Block.init(rp.c, scope, null); block_scope.?.block_node = try transCreateNodeBlock(rp.c, null); - inner = &block_scope.?.base; - _ = try transStmt(rp, inner, init, .unused, .r_value); + loop_scope.parent = &block_scope.?.base; + _ = try transStmt(rp, &loop_scope, init, .unused, .r_value); } - var cond_scope = Scope.Condition{ - .base = .{ - .parent = inner, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; const while_node = try transCreateNodeWhile(rp.c); while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| - try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false) + try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false) else try transCreateNodeBoolLiteral(rp.c, true); _ = try appendToken(rp.c, .RParen, ")"); @@ -1589,11 +1586,11 @@ fn transForLoop( if (ZigClangForStmt_getInc(stmt)) |incr| { _ = try appendToken(rp.c, .Colon, ":"); _ = try appendToken(rp.c, .LParen, "("); - while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value); + while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value); _ = try appendToken(rp.c, .RParen, ")"); } - while_node.body = try transStmt(rp, inner, ZigClangForStmt_getBody(stmt), .unused, .r_value); + while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); if (block_scope != null) { try block_scope.?.block_node.statements.push(&while_node.base); block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); @@ -1617,13 +1614,11 @@ fn transSwitch( .pending_block = undefined, }; - var cond_scope = Scope.Condition{ - .base = .{ - .parent = scope, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; - switch_node.expr = try transExpr(rp, &cond_scope.base, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); + switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); _ = try appendToken(rp.c, .RParen, ")"); _ = try appendToken(rp.c, .LBrace, "{"); switch_node.rbrace = try appendToken(rp.c, .RBrace, "}"); @@ -1753,6 +1748,41 @@ fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPre return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used); } +fn transCharLiteral( + rp: RestorePoint, + scope: *Scope, + stmt: *const ZigClangCharacterLiteral, + result_used: ResultUsed, +) TransError!*ast.Node { + const kind = ZigClangCharacterLiteral_getKind(stmt); + switch (kind) { + .Ascii, .UTF8 => { + 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); + } + var char_buf: [4]u8 = undefined; + const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); + const node = try rp.c.a().create(ast.Node.CharLiteral); + node.* = .{ + .token = token, + }; + return maybeSuppressResult(rp, scope, result_used, &node.base); + }, + .UTF16, .UTF32, .Wide => return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), + "TODO: support character literal kind {}", + .{kind}, + ), + else => unreachable, + } +} + fn transCPtrCast( rp: RestorePoint, loc: ZigClangSourceLocation, @@ -1796,6 +1826,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { "__switch" else null); + _ = try appendToken(rp.c, .Semicolon, ";"); return &br.base; } @@ -1813,18 +1844,16 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla const gropued = scope.id == .Condition; const lparen = if (gropued) try appendToken(rp.c, .LParen, "(") else undefined; const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope.Condition{ - .base = .{ - .parent = scope, - .id = .Condition, - }, + var cond_scope = Scope{ + .parent = scope, + .id = .Condition, }; const cond_expr = ZigClangConditionalOperator_getCond(stmt); const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt); const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt); - if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); + if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); @@ -3104,7 +3133,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { var tok_it = tok_list.iterator(0); const first_tok = tok_it.next().?; - assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, checked_name)); + assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name)); const next = tok_it.peek().?; switch (next.id) { .Identifier => { diff --git a/test/translate_c.zig b/test/translate_c.zig index aebeddc856..6191dabe02 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -600,6 +600,135 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_both("simple union", + \\union Foo { + \\ int x; + \\ double y; + \\}; + , &[_][]const u8{ + \\pub const union_Foo = extern union { + \\ x: c_int, + \\ y: f64, + \\}; + , + \\pub const Foo = union_Foo; + }); + + cases.addC_both("string literal", + \\const char *foo(void) { + \\ return "bar"; + \\} + , &[_][]const u8{ + \\pub export fn foo() [*c]const u8 { + \\ return "bar"; + \\} + }); + + cases.addC_both("return void", + \\void foo(void) { + \\ return; + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ return; + \\} + }); + + cases.addC_both("for loop", + \\void foo(void) { + \\ for (int i = 0; i; i = i + 1) { } + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ { + \\ var i: c_int = 0; + \\ while (i != 0) : (i = (i + 1)) {} + \\ } + \\} + }); + + cases.addC_both("empty for loop", + \\void foo(void) { + \\ for (;;) { } + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ while (true) {} + \\} + }); + + cases.addC_both("break statement", + \\void foo(void) { + \\ for (;;) { + \\ break; + \\ } + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ while (true) { + \\ break; + \\ } + \\} + }); + + cases.addC_both("continue statement", + \\void foo(void) { + \\ for (;;) { + \\ continue; + \\ } + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ while (true) { + \\ continue; + \\ } + \\} + }); + + cases.addC_both("pointer casting", + \\float *ptrcast(int *a) { + \\ return (float *)a; + \\} + , &[_][]const u8{ + \\pub export fn ptrcast(a: [*c]c_int) [*c]f32 { + \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); + \\} + }); + + cases.addC_both("pointer conversion with different alignment", + \\void test_ptr_cast() { + \\ void *p; + \\ { + \\ char *to_char = (char *)p; + \\ short *to_short = (short *)p; + \\ int *to_int = (int *)p; + \\ long long *to_longlong = (long long *)p; + \\ } + \\ { + \\ char *to_char = p; + \\ short *to_short = p; + \\ int *to_int = p; + \\ long long *to_longlong = p; + \\ } + \\} + , &[_][]const u8{ + \\pub export fn test_ptr_cast() void { + \\ var p: ?*c_void = undefined; + \\ { + \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); + \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); + \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); + \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); + \\ } + \\ { + \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); + \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); + \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); + \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); + \\ } + \\} + }); + /////////////// Cases that pass for only stage2 //////////////// cases.add_2("Parameterless function prototypes", @@ -957,11 +1086,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ while (true) { \\ var a: c_int = 2; \\ a = 12; - \\ if (!4 != 0) break; + \\ if (!(4 != 0)) break; \\ } \\ while (true) { \\ a = 7; - \\ if (!4 != 0) break; + \\ if (!(4 != 0)) break; \\ } \\} }); @@ -1145,6 +1274,66 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("escape sequences", + \\const char *escapes() { + \\char a = '\'', + \\ b = '\\', + \\ c = '\a', + \\ d = '\b', + \\ e = '\f', + \\ f = '\n', + \\ g = '\r', + \\ h = '\t', + \\ i = '\v', + \\ j = '\0', + \\ k = '\"'; + \\ return "\'\\\a\b\f\n\r\t\v\0\""; + \\} + \\ + , &[_][]const u8{ + \\pub export fn escapes() [*c]const u8 { + \\ var a: u8 = @as(u8, '\''); + \\ var b: u8 = @as(u8, '\\'); + \\ var c: u8 = @as(u8, '\x07'); + \\ var d: u8 = @as(u8, '\x08'); + \\ var e: u8 = @as(u8, '\x0c'); + \\ var f: u8 = @as(u8, '\n'); + \\ var g: u8 = @as(u8, '\r'); + \\ var h: u8 = @as(u8, '\t'); + \\ var i: u8 = @as(u8, '\x0b'); + \\ var j: u8 = @as(u8, '\x00'); + \\ var k: u8 = @as(u8, '\"'); + \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; + \\} + }); + + cases.add_2("do loop", + \\void foo(void) { + \\ int a = 2; + \\ do { + \\ a = a - 1; + \\ } while (a); + \\ + \\ int b = 2; + \\ do + \\ b = b -1; + \\ while (b); + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: c_int = 2; + \\ while (true) { + \\ a = (a - 1); + \\ if (!(a != 0)) break; + \\ } + \\ var b: c_int = 2; + \\ while (true) { + \\ b = (b - 1); + \\ if (!(b != 0)) break; + \\ } + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.addAllowWarnings("simple data types", @@ -1641,33 +1830,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("do loop", - \\void foo(void) { - \\ int a = 2; - \\ do { - \\ a--; - \\ } while (a != 0); - \\ - \\ int b = 2; - \\ do - \\ b--; - \\ while (b != 0); - \\} - , &[_][]const u8{ - \\pub export fn foo() void { - \\ var a: c_int = 2; - \\ while (true) { - \\ a -= 1; - \\ if (!(a != 0)) break; - \\ } - \\ var b: c_int = 2; - \\ while (true) { - \\ b -= 1; - \\ if (!(b != 0)) break; - \\ } - \\} - }); - cases.addC("deref function pointer", \\void foo(void) {} \\int baz(void) { return 0; } @@ -1708,20 +1870,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("simple union", - \\union Foo { - \\ int x; - \\ double y; - \\}; - , &[_][]const u8{ - \\pub const union_Foo = extern union { - \\ x: c_int, - \\ y: f64, - \\}; - , - \\pub const Foo = union_Foo; - }); - cases.add("address of operator", \\int foo(void) { \\ int x = 1234; @@ -1736,77 +1884,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("string literal", - \\const char *foo(void) { - \\ return "bar"; - \\} - , &[_][]const u8{ - \\pub fn foo() [*c]const u8 { - \\ return "bar"; - \\} - }); - - cases.add("return void", - \\void foo(void) { - \\ return; - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ return; - \\} - }); - - cases.add("for loop", - \\void foo(void) { - \\ for (int i = 0; i < 10; i += 1) { } - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ { - \\ var i: c_int = 0; - \\ while (i < 10) : (i += 1) {} - \\ } - \\} - }); - - cases.add("empty for loop", - \\void foo(void) { - \\ for (;;) { } - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ while (true) {} - \\} - }); - - cases.add("break statement", - \\void foo(void) { - \\ for (;;) { - \\ break; - \\ } - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ while (true) { - \\ break; - \\ } - \\} - }); - - cases.add("continue statement", - \\void foo(void) { - \\ for (;;) { - \\ continue; - \\ } - \\} - , &[_][]const u8{ - \\pub fn foo() void { - \\ while (true) { - \\ continue; - \\ } - \\} - }); - cases.add("variable name shadowing", \\int foo(void) { \\ int x = 1; @@ -1827,16 +1904,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("pointer casting", - \\float *ptrcast(int *a) { - \\ return (float *)a; - \\} - , &[_][]const u8{ - \\fn ptrcast(a: [*c]c_int) [*c]f32 { - \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); - \\} - }); - cases.add("bin not", \\int foo(int x) { \\ return ~x; @@ -1987,74 +2054,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.addC("pointer conversion with different alignment", - \\void test_ptr_cast() { - \\ void *p; - \\ { - \\ char *to_char = (char *)p; - \\ short *to_short = (short *)p; - \\ int *to_int = (int *)p; - \\ long long *to_longlong = (long long *)p; - \\ } - \\ { - \\ char *to_char = p; - \\ short *to_short = p; - \\ int *to_int = p; - \\ long long *to_longlong = p; - \\ } - \\} - , &[_][]const u8{ - \\pub export fn test_ptr_cast() void { - \\ var p: ?*c_void = undefined; - \\ { - \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); - \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); - \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); - \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); - \\ } - \\ { - \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); - \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); - \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); - \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); - \\ } - \\} - }); - - cases.addC("escape sequences", - \\const char *escapes() { - \\char a = '\'', - \\ b = '\\', - \\ c = '\a', - \\ d = '\b', - \\ e = '\f', - \\ f = '\n', - \\ g = '\r', - \\ h = '\t', - \\ i = '\v', - \\ j = '\0', - \\ k = '\"'; - \\ return "\'\\\a\b\f\n\r\t\v\0\""; - \\} - \\ - , &[_][]const u8{ - \\pub export fn escapes() [*c]const u8 { - \\ var a: u8 = @as(u8, '\''); - \\ var b: u8 = @as(u8, '\\'); - \\ var c: u8 = @as(u8, '\x07'); - \\ var d: u8 = @as(u8, '\x08'); - \\ var e: u8 = @as(u8, '\x0c'); - \\ var f: u8 = @as(u8, '\n'); - \\ var g: u8 = @as(u8, '\r'); - \\ var h: u8 = @as(u8, '\t'); - \\ var i: u8 = @as(u8, '\x0b'); - \\ var j: u8 = @as(u8, '\x00'); - \\ var k: u8 = @as(u8, '\"'); - \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; - \\} - \\ - }); - if (builtin.os != builtin.Os.windows) { // sysv_abi not currently supported on windows cases.add("Macro qualified functions", @@ -2386,4 +2385,65 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ }; \\} }); + + cases.addC("escape sequences", + \\const char *escapes() { + \\char a = '\'', + \\ b = '\\', + \\ c = '\a', + \\ d = '\b', + \\ e = '\f', + \\ f = '\n', + \\ g = '\r', + \\ h = '\t', + \\ i = '\v', + \\ j = '\0', + \\ k = '\"'; + \\ return "\'\\\a\b\f\n\r\t\v\0\""; + \\} + \\ + , &[_][]const u8{ + \\pub export fn escapes() [*c]const u8 { + \\ var a: u8 = @as(u8, '\''); + \\ var b: u8 = @as(u8, '\\'); + \\ var c: u8 = @as(u8, '\x07'); + \\ var d: u8 = @as(u8, '\x08'); + \\ var e: u8 = @as(u8, '\x0c'); + \\ var f: u8 = @as(u8, '\n'); + \\ var g: u8 = @as(u8, '\r'); + \\ var h: u8 = @as(u8, '\t'); + \\ var i: u8 = @as(u8, '\x0b'); + \\ var j: u8 = @as(u8, '\x00'); + \\ var k: u8 = @as(u8, '\"'); + \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; + \\} + \\ + }); + + cases.addC("do loop", + \\void foo(void) { + \\ int a = 2; + \\ do { + \\ a--; + \\ } while (a != 0); + \\ + \\ int b = 2; + \\ do + \\ b--; + \\ while (b != 0); + \\} + , &[_][]const u8{ + \\pub export fn foo() void { + \\ var a: c_int = 2; + \\ while (true) { + \\ a -= 1; + \\ if (!(a != 0)) break; + \\ } + \\ var b: c_int = 2; + \\ while (true) { + \\ b -= 1; + \\ if (!(b != 0)) break; + \\ } + \\} + }); }