| author | |
| committer | |
| log | f3d174aa616401117927988dfc499a1762db01a3 |
| tree | db105e8ce4b8766025f4a3e04357b7e507698497 |
| parent | b971c7d0ff1c0ef86ac8d6816eb5e115f0d648fa |
| signature |
4 files changed, 68 insertions(+), 48 deletions(-)
src-self-hosted/translate_c.zig+26-37| ... | ... | @@ -289,8 +289,7 @@ pub fn translate( |
| 289 | 289 | tree.errors = ast.Tree.ErrorList.init(arena); |
| 290 | 290 | |
| 291 | 291 | tree.root_node = try arena.create(ast.Node.Root); |
| 292 | tree.root_node.* = ast.Node.Root{ | |
| 293 | .base = ast.Node{ .id = ast.Node.Id.Root }, | |
| 292 | tree.root_node.* = .{ | |
| 294 | 293 | .decls = ast.Node.Root.DeclList.init(arena), |
| 295 | 294 | // initialized with the eof token at the end |
| 296 | 295 | .eof_token = undefined, |
| ... | ... | @@ -876,25 +875,20 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 876 | 875 | // types, while that's not ISO-C compliant many compilers allow this and |
| 877 | 876 | // default to the usual integer type used for all the enums. |
| 878 | 877 | |
| 879 | // TODO only emit this tag type if the enum tag type is not the default. | |
| 880 | // I don't know what the default is, need to figure out how clang is deciding. | |
| 881 | // it appears to at least be different across gcc/msvc | |
| 882 | if (int_type.ptr != null and | |
| 883 | !isCBuiltinType(int_type, .UInt) and | |
| 884 | !isCBuiltinType(int_type, .Int)) | |
| 885 | { | |
| 886 | _ = try appendToken(c, .LParen, "("); | |
| 887 | container_node.init_arg_expr = .{ | |
| 888 | .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { | |
| 878 | _ = try appendToken(c, .LParen, "("); | |
| 879 | container_node.init_arg_expr = .{ | |
| 880 | .Type = if (int_type.ptr != null) | |
| 881 | transQualType(rp, int_type, enum_loc) catch |err| switch (err) { | |
| 889 | 882 | error.UnsupportedType => { |
| 890 | 883 | try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); |
| 891 | 884 | return null; |
| 892 | 885 | }, |
| 893 | 886 | else => |e| return e, |
| 894 | }, | |
| 895 | }; | |
| 896 | _ = try appendToken(c, .RParen, ")"); | |
| 897 | } | |
| 887 | } | |
| 888 | else | |
| 889 | try transCreateNodeIdentifier(c, "c_int"), | |
| 890 | }; | |
| 891 | _ = try appendToken(c, .RParen, ")"); | |
| 898 | 892 | |
| 899 | 893 | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); |
| 900 | 894 | |
| ... | ... | @@ -2198,6 +2192,19 @@ fn transDoWhileLoop( |
| 2198 | 2192 | .id = .Loop, |
| 2199 | 2193 | }; |
| 2200 | 2194 | |
| 2195 | // if (!cond) break; | |
| 2196 | const if_node = try transCreateNodeIf(rp.c); | |
| 2197 | var cond_scope = Scope{ | |
| 2198 | .parent = scope, | |
| 2199 | .id = .Condition, | |
| 2200 | }; | |
| 2201 | const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); | |
| 2202 | prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); | |
| 2203 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 2204 | if_node.condition = &prefix_op.base; | |
| 2205 | if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; | |
| 2206 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2207 | ||
| 2201 | 2208 | const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: { |
| 2202 | 2209 | // there's already a block in C, so we'll append our condition to it. |
| 2203 | 2210 | // c: do { |
| ... | ... | @@ -2209,10 +2216,7 @@ fn transDoWhileLoop( |
| 2209 | 2216 | // zig: b; |
| 2210 | 2217 | // zig: if (!cond) break; |
| 2211 | 2218 | // zig: } |
| 2212 | const body = (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; | |
| 2213 | // if this is used as an expression in Zig it needs to be immediately followed by a semicolon | |
| 2214 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2215 | break :blk body; | |
| 2219 | break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; | |
| 2216 | 2220 | } else blk: { |
| 2217 | 2221 | // the C statement is without a block, so we need to create a block to contain it. |
| 2218 | 2222 | // c: do |
| ... | ... | @@ -2228,19 +2232,6 @@ fn transDoWhileLoop( |
| 2228 | 2232 | break :blk block; |
| 2229 | 2233 | }; |
| 2230 | 2234 | |
| 2231 | // if (!cond) break; | |
| 2232 | const if_node = try transCreateNodeIf(rp.c); | |
| 2233 | var cond_scope = Scope{ | |
| 2234 | .parent = scope, | |
| 2235 | .id = .Condition, | |
| 2236 | }; | |
| 2237 | const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); | |
| 2238 | prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); | |
| 2239 | _ = try appendToken(rp.c, .RParen, ")"); | |
| 2240 | if_node.condition = &prefix_op.base; | |
| 2241 | if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; | |
| 2242 | _ = try appendToken(rp.c, .Semicolon, ";"); | |
| 2243 | ||
| 2244 | 2235 | try body_node.statements.push(&if_node.base); |
| 2245 | 2236 | if (new) |
| 2246 | 2237 | body_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| ... | ... | @@ -4775,8 +4766,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { |
| 4775 | 4766 | fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { |
| 4776 | 4767 | const token_index = try appendIdentifier(c, name); |
| 4777 | 4768 | const identifier = try c.a().create(ast.Node.Identifier); |
| 4778 | identifier.* = ast.Node.Identifier{ | |
| 4779 | .base = ast.Node{ .id = ast.Node.Id.Identifier }, | |
| 4769 | identifier.* = .{ | |
| 4780 | 4770 | .token = token_index, |
| 4781 | 4771 | }; |
| 4782 | 4772 | return &identifier.base; |
| ... | ... | @@ -4915,8 +4905,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u |
| 4915 | 4905 | |
| 4916 | 4906 | const token_index = try appendToken(c, .Keyword_var, "var"); |
| 4917 | 4907 | const identifier = try c.a().create(ast.Node.Identifier); |
| 4918 | identifier.* = ast.Node.Identifier{ | |
| 4919 | .base = ast.Node{ .id = ast.Node.Id.Identifier }, | |
| 4908 | identifier.* = .{ | |
| 4920 | 4909 | .token = token_index, |
| 4921 | 4910 | }; |
| 4922 | 4911 |
src/analyze.cpp+8| ... | ... | @@ -2652,6 +2652,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2652 | 2652 | AstNode *tag_value = field_node->data.struct_field.value; |
| 2653 | 2653 | |
| 2654 | 2654 | if (buf_eql_str(type_enum_field->name, "_")) { |
| 2655 | if (decl_node->data.container_decl.init_arg_expr == nullptr) { | |
| 2656 | add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size")); | |
| 2657 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2658 | } | |
| 2659 | if (log2_u64(field_count - 1) == enum_type->size_in_bits) { | |
| 2660 | add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value")); | |
| 2661 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2662 | } | |
| 2655 | 2663 | if (field_i != field_count - 1) { |
| 2656 | 2664 | add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last")); |
| 2657 | 2665 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; |
test/compile_errors.zig+24-1| ... | ... | @@ -3,7 +3,30 @@ const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | 5 | cases.addTest("non-exhaustive enums", |
| 6 | \\const E = enum { | |
| 6 | \\const A = enum { | |
| 7 | \\ a, | |
| 8 | \\ b, | |
| 9 | \\ _ = 1, | |
| 10 | \\}; | |
| 11 | \\const B = enum(u1) { | |
| 12 | \\ a, | |
| 13 | \\ b, | |
| 14 | \\ _, | |
| 15 | \\ c, | |
| 16 | \\}; | |
| 17 | \\pub export fn entry() void { | |
| 18 | \\ _ = A; | |
| 19 | \\ _ = B; | |
| 20 | \\} | |
| 21 | , &[_][]const u8{ | |
| 22 | "tmp.zig:4:5: error: non-exhaustive enum must specify size", | |
| 23 | "error: value assigned to '_' field of non-exhaustive enum", | |
| 24 | "error: non-exhaustive enum specifies every value", | |
| 25 | "error: '_' field of non-exhaustive enum must be last", | |
| 26 | }); | |
| 27 | ||
| 28 | cases.addTest("switching with non-exhaustive enums", | |
| 29 | \\const E = enum(u8) { | |
| 7 | 30 | \\ a, |
| 8 | 31 | \\ b, |
| 9 | 32 | \\ _, |
test/translate_c.zig+10-10| ... | ... | @@ -989,7 +989,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 989 | 989 | \\enum enum_ty { FOO }; |
| 990 | 990 | , &[_][]const u8{ |
| 991 | 991 | \\pub const FOO = @enumToInt(enum_enum_ty.FOO); |
| 992 | \\pub const enum_enum_ty = extern enum { | |
| 992 | \\pub const enum_enum_ty = extern enum(c_int) { | |
| 993 | 993 | \\ FOO, |
| 994 | 994 | \\ _, |
| 995 | 995 | \\}; |
| ... | ... | @@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1104 | 1104 | \\pub const a = @enumToInt(enum_unnamed_1.a); |
| 1105 | 1105 | \\pub const b = @enumToInt(enum_unnamed_1.b); |
| 1106 | 1106 | \\pub const c = @enumToInt(enum_unnamed_1.c); |
| 1107 | \\const enum_unnamed_1 = extern enum { | |
| 1107 | \\const enum_unnamed_1 = extern enum(c_uint) { | |
| 1108 | 1108 | \\ a, |
| 1109 | 1109 | \\ b, |
| 1110 | 1110 | \\ c, |
| ... | ... | @@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1114 | 1114 | \\pub const e = @enumToInt(enum_unnamed_2.e); |
| 1115 | 1115 | \\pub const f = @enumToInt(enum_unnamed_2.f); |
| 1116 | 1116 | \\pub const g = @enumToInt(enum_unnamed_2.g); |
| 1117 | \\const enum_unnamed_2 = extern enum { | |
| 1117 | \\const enum_unnamed_2 = extern enum(c_uint) { | |
| 1118 | 1118 | \\ e = 0, |
| 1119 | 1119 | \\ f = 4, |
| 1120 | 1120 | \\ g = 5, |
| ... | ... | @@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1124 | 1124 | \\pub const i = @enumToInt(enum_unnamed_3.i); |
| 1125 | 1125 | \\pub const j = @enumToInt(enum_unnamed_3.j); |
| 1126 | 1126 | \\pub const k = @enumToInt(enum_unnamed_3.k); |
| 1127 | \\const enum_unnamed_3 = extern enum { | |
| 1127 | \\const enum_unnamed_3 = extern enum(c_uint) { | |
| 1128 | 1128 | \\ i, |
| 1129 | 1129 | \\ j, |
| 1130 | 1130 | \\ k, |
| ... | ... | @@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1137 | 1137 | \\pub const n = @enumToInt(enum_i.n); |
| 1138 | 1138 | \\pub const o = @enumToInt(enum_i.o); |
| 1139 | 1139 | \\pub const p = @enumToInt(enum_i.p); |
| 1140 | \\pub const enum_i = extern enum { | |
| 1140 | \\pub const enum_i = extern enum(c_uint) { | |
| 1141 | 1141 | \\ n, |
| 1142 | 1142 | \\ o, |
| 1143 | 1143 | \\ p, |
| ... | ... | @@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1569 | 1569 | , &[_][]const u8{ |
| 1570 | 1570 | \\pub const One = @enumToInt(enum_unnamed_1.One); |
| 1571 | 1571 | \\pub const Two = @enumToInt(enum_unnamed_1.Two); |
| 1572 | \\const enum_unnamed_1 = extern enum { | |
| 1572 | \\const enum_unnamed_1 = extern enum(c_uint) { | |
| 1573 | 1573 | \\ One, |
| 1574 | 1574 | \\ Two, |
| 1575 | 1575 | \\ _, |
| ... | ... | @@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1672 | 1672 | \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p); |
| 1673 | 1673 | \\} |
| 1674 | 1674 | , &[_][]const u8{ |
| 1675 | \\pub const enum_Foo = extern enum { | |
| 1675 | \\pub const enum_Foo = extern enum(c_uint) { | |
| 1676 | 1676 | \\ A, |
| 1677 | 1677 | \\ B, |
| 1678 | 1678 | \\ C, |
| ... | ... | @@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1718 | 1718 | \\ y: c_int, |
| 1719 | 1719 | \\}; |
| 1720 | 1720 | , |
| 1721 | \\pub const enum_Bar = extern enum { | |
| 1721 | \\pub const enum_Bar = extern enum(c_uint) { | |
| 1722 | 1722 | \\ A, |
| 1723 | 1723 | \\ B, |
| 1724 | 1724 | \\ _, |
| ... | ... | @@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1982 | 1982 | \\ return 4; |
| 1983 | 1983 | \\} |
| 1984 | 1984 | , &[_][]const u8{ |
| 1985 | \\pub const enum_SomeEnum = extern enum { | |
| 1985 | \\pub const enum_SomeEnum = extern enum(c_uint) { | |
| 1986 | 1986 | \\ A, |
| 1987 | 1987 | \\ B, |
| 1988 | 1988 | \\ C, |
| ... | ... | @@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2424 | 2424 | \\pub const FooA = @enumToInt(enum_Foo.A); |
| 2425 | 2425 | \\pub const FooB = @enumToInt(enum_Foo.B); |
| 2426 | 2426 | \\pub const Foo1 = @enumToInt(enum_Foo.@"1"); |
| 2427 | \\pub const enum_Foo = extern enum { | |
| 2427 | \\pub const enum_Foo = extern enum(c_uint) { | |
| 2428 | 2428 | \\ A = 2, |
| 2429 | 2429 | \\ B = 5, |
| 2430 | 2430 | \\ @"1" = 6, |