authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-15 21:38:11+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-01-15 21:38:11+02:00
logf3d174aa616401117927988dfc499a1762db01a3
treedb105e8ce4b8766025f4a3e04357b7e507698497
parentb971c7d0ff1c0ef86ac8d6816eb5e115f0d648fa
signaturelock-open Commit is signed but in an unrecognized format.

require size for non-exhaustive enums


4 files changed, 68 insertions(+), 48 deletions(-)

src-self-hosted/translate_c.zig+26-37
......@@ -289,8 +289,7 @@ pub fn translate(
289289 tree.errors = ast.Tree.ErrorList.init(arena);
290290
291291 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.* = .{
294293 .decls = ast.Node.Root.DeclList.init(arena),
295294 // initialized with the eof token at the end
296295 .eof_token = undefined,
......@@ -876,25 +875,20 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
876875 // types, while that's not ISO-C compliant many compilers allow this and
877876 // default to the usual integer type used for all the enums.
878877
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) {
889882 error.UnsupportedType => {
890883 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
891884 return null;
892885 },
893886 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, ")");
898892
899893 container_node.lbrace_token = try appendToken(c, .LBrace, "{");
900894
......@@ -2198,6 +2192,19 @@ fn transDoWhileLoop(
21982192 .id = .Loop,
21992193 };
22002194
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
22012208 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
22022209 // there's already a block in C, so we'll append our condition to it.
22032210 // c: do {
......@@ -2209,10 +2216,7 @@ fn transDoWhileLoop(
22092216 // zig: b;
22102217 // zig: if (!cond) break;
22112218 // 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).?;
22162220 } else blk: {
22172221 // the C statement is without a block, so we need to create a block to contain it.
22182222 // c: do
......@@ -2228,19 +2232,6 @@ fn transDoWhileLoop(
22282232 break :blk block;
22292233 };
22302234
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
22442235 try body_node.statements.push(&if_node.base);
22452236 if (new)
22462237 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
......@@ -4775,8 +4766,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
47754766fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
47764767 const token_index = try appendIdentifier(c, name);
47774768 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.* = .{
47804770 .token = token_index,
47814771 };
47824772 return &identifier.base;
......@@ -4915,8 +4905,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
49154905
49164906 const token_index = try appendToken(c, .Keyword_var, "var");
49174907 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.* = .{
49204909 .token = token_index,
49214910 };
49224911
src/analyze.cpp+8
......@@ -2652,6 +2652,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
26522652 AstNode *tag_value = field_node->data.struct_field.value;
26532653
26542654 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 }
26552663 if (field_i != field_count - 1) {
26562664 add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
26572665 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
test/compile_errors.zig+24-1
......@@ -3,7 +3,30 @@ const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
55 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) {
730 \\ a,
831 \\ b,
932 \\ _,
test/translate_c.zig+10-10
......@@ -989,7 +989,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
989989 \\enum enum_ty { FOO };
990990 , &[_][]const u8{
991991 \\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) {
993993 \\ FOO,
994994 \\ _,
995995 \\};
......@@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11041104 \\pub const a = @enumToInt(enum_unnamed_1.a);
11051105 \\pub const b = @enumToInt(enum_unnamed_1.b);
11061106 \\pub const c = @enumToInt(enum_unnamed_1.c);
1107 \\const enum_unnamed_1 = extern enum {
1107 \\const enum_unnamed_1 = extern enum(c_uint) {
11081108 \\ a,
11091109 \\ b,
11101110 \\ c,
......@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11141114 \\pub const e = @enumToInt(enum_unnamed_2.e);
11151115 \\pub const f = @enumToInt(enum_unnamed_2.f);
11161116 \\pub const g = @enumToInt(enum_unnamed_2.g);
1117 \\const enum_unnamed_2 = extern enum {
1117 \\const enum_unnamed_2 = extern enum(c_uint) {
11181118 \\ e = 0,
11191119 \\ f = 4,
11201120 \\ g = 5,
......@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11241124 \\pub const i = @enumToInt(enum_unnamed_3.i);
11251125 \\pub const j = @enumToInt(enum_unnamed_3.j);
11261126 \\pub const k = @enumToInt(enum_unnamed_3.k);
1127 \\const enum_unnamed_3 = extern enum {
1127 \\const enum_unnamed_3 = extern enum(c_uint) {
11281128 \\ i,
11291129 \\ j,
11301130 \\ k,
......@@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
11371137 \\pub const n = @enumToInt(enum_i.n);
11381138 \\pub const o = @enumToInt(enum_i.o);
11391139 \\pub const p = @enumToInt(enum_i.p);
1140 \\pub const enum_i = extern enum {
1140 \\pub const enum_i = extern enum(c_uint) {
11411141 \\ n,
11421142 \\ o,
11431143 \\ p,
......@@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15691569 , &[_][]const u8{
15701570 \\pub const One = @enumToInt(enum_unnamed_1.One);
15711571 \\pub const Two = @enumToInt(enum_unnamed_1.Two);
1572 \\const enum_unnamed_1 = extern enum {
1572 \\const enum_unnamed_1 = extern enum(c_uint) {
15731573 \\ One,
15741574 \\ Two,
15751575 \\ _,
......@@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16721672 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
16731673 \\}
16741674 , &[_][]const u8{
1675 \\pub const enum_Foo = extern enum {
1675 \\pub const enum_Foo = extern enum(c_uint) {
16761676 \\ A,
16771677 \\ B,
16781678 \\ C,
......@@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17181718 \\ y: c_int,
17191719 \\};
17201720 ,
1721 \\pub const enum_Bar = extern enum {
1721 \\pub const enum_Bar = extern enum(c_uint) {
17221722 \\ A,
17231723 \\ B,
17241724 \\ _,
......@@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19821982 \\ return 4;
19831983 \\}
19841984 , &[_][]const u8{
1985 \\pub const enum_SomeEnum = extern enum {
1985 \\pub const enum_SomeEnum = extern enum(c_uint) {
19861986 \\ A,
19871987 \\ B,
19881988 \\ C,
......@@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
24242424 \\pub const FooA = @enumToInt(enum_Foo.A);
24252425 \\pub const FooB = @enumToInt(enum_Foo.B);
24262426 \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
2427 \\pub const enum_Foo = extern enum {
2427 \\pub const enum_Foo = extern enum(c_uint) {
24282428 \\ A = 2,
24292429 \\ B = 5,
24302430 \\ @"1" = 6,