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
signature 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(...@@ -289,8 +289,7 @@ pub fn translate(
289 tree.errors = ast.Tree.ErrorList.init(arena);289 tree.errors = ast.Tree.ErrorList.init(arena);
290290
291 tree.root_node = try arena.create(ast.Node.Root);291 tree.root_node = try arena.create(ast.Node.Root);
292 tree.root_node.* = ast.Node.Root{292 tree.root_node.* = .{
293 .base = ast.Node{ .id = ast.Node.Id.Root },
294 .decls = ast.Node.Root.DeclList.init(arena),293 .decls = ast.Node.Root.DeclList.init(arena),
295 // initialized with the eof token at the end294 // initialized with the eof token at the end
296 .eof_token = undefined,295 .eof_token = undefined,
...@@ -876,25 +875,20 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No...@@ -876,25 +875,20 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
876 // types, while that's not ISO-C compliant many compilers allow this and875 // types, while that's not ISO-C compliant many compilers allow this and
877 // default to the usual integer type used for all the enums.876 // 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.878 _ = try appendToken(c, .LParen, "(");
880 // I don't know what the default is, need to figure out how clang is deciding.879 container_node.init_arg_expr = .{
881 // it appears to at least be different across gcc/msvc880 .Type = if (int_type.ptr != null)
882 if (int_type.ptr != null and881 transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
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) {
889 error.UnsupportedType => {882 error.UnsupportedType => {
890 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});883 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
891 return null;884 return null;
892 },885 },
893 else => |e| return e,886 else => |e| return e,
894 },887 }
895 };888 else
896 _ = try appendToken(c, .RParen, ")");889 try transCreateNodeIdentifier(c, "c_int"),
897 }890 };
891 _ = try appendToken(c, .RParen, ")");
898892
899 container_node.lbrace_token = try appendToken(c, .LBrace, "{");893 container_node.lbrace_token = try appendToken(c, .LBrace, "{");
900894
...@@ -2198,6 +2192,19 @@ fn transDoWhileLoop(...@@ -2198,6 +2192,19 @@ fn transDoWhileLoop(
2198 .id = .Loop,2192 .id = .Loop,
2199 };2193 };
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
2201 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {2208 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
2202 // there's already a block in C, so we'll append our condition to it.2209 // there's already a block in C, so we'll append our condition to it.
2203 // c: do {2210 // c: do {
...@@ -2209,10 +2216,7 @@ fn transDoWhileLoop(...@@ -2209,10 +2216,7 @@ fn transDoWhileLoop(
2209 // zig: b;2216 // zig: b;
2210 // zig: if (!cond) break;2217 // zig: if (!cond) break;
2211 // zig: }2218 // zig: }
2212 const body = (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;2219 break :blk (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;
2216 } else blk: {2220 } else blk: {
2217 // the C statement is without a block, so we need to create a block to contain it.2221 // the C statement is without a block, so we need to create a block to contain it.
2218 // c: do2222 // c: do
...@@ -2228,19 +2232,6 @@ fn transDoWhileLoop(...@@ -2228,19 +2232,6 @@ fn transDoWhileLoop(
2228 break :blk block;2232 break :blk block;
2229 };2233 };
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
2244 try body_node.statements.push(&if_node.base);2235 try body_node.statements.push(&if_node.base);
2245 if (new)2236 if (new)
2246 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");2237 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
...@@ -4775,8 +4766,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {...@@ -4775,8 +4766,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
4775fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {4766fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
4776 const token_index = try appendIdentifier(c, name);4767 const token_index = try appendIdentifier(c, name);
4777 const identifier = try c.a().create(ast.Node.Identifier);4768 const identifier = try c.a().create(ast.Node.Identifier);
4778 identifier.* = ast.Node.Identifier{4769 identifier.* = .{
4779 .base = ast.Node{ .id = ast.Node.Id.Identifier },
4780 .token = token_index,4770 .token = token_index,
4781 };4771 };
4782 return &identifier.base;4772 return &identifier.base;
...@@ -4915,8 +4905,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u...@@ -4915,8 +4905,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
49154905
4916 const token_index = try appendToken(c, .Keyword_var, "var");4906 const token_index = try appendToken(c, .Keyword_var, "var");
4917 const identifier = try c.a().create(ast.Node.Identifier);4907 const identifier = try c.a().create(ast.Node.Identifier);
4918 identifier.* = ast.Node.Identifier{4908 identifier.* = .{
4919 .base = ast.Node{ .id = ast.Node.Id.Identifier },
4920 .token = token_index,4909 .token = token_index,
4921 };4910 };
49224911
src/analyze.cpp+8
...@@ -2652,6 +2652,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2652,6 +2652,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2652 AstNode *tag_value = field_node->data.struct_field.value;2652 AstNode *tag_value = field_node->data.struct_field.value;
26532653
2654 if (buf_eql_str(type_enum_field->name, "_")) {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 if (field_i != field_count - 1) {2663 if (field_i != field_count - 1) {
2656 add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));2664 add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
2657 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;2665 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
test/compile_errors.zig+24-1
...@@ -3,7 +3,30 @@ const builtin = @import("builtin");...@@ -3,7 +3,30 @@ const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("non-exhaustive enums",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 \\ a,30 \\ a,
8 \\ b,31 \\ b,
9 \\ _,32 \\ _,
test/translate_c.zig+10-10
...@@ -989,7 +989,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -989,7 +989,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
989 \\enum enum_ty { FOO };989 \\enum enum_ty { FOO };
990 , &[_][]const u8{990 , &[_][]const u8{
991 \\pub const FOO = @enumToInt(enum_enum_ty.FOO);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 \\ FOO,993 \\ FOO,
994 \\ _,994 \\ _,
995 \\};995 \\};
...@@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1104 \\pub const a = @enumToInt(enum_unnamed_1.a);1104 \\pub const a = @enumToInt(enum_unnamed_1.a);
1105 \\pub const b = @enumToInt(enum_unnamed_1.b);1105 \\pub const b = @enumToInt(enum_unnamed_1.b);
1106 \\pub const c = @enumToInt(enum_unnamed_1.c);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 \\ a,1108 \\ a,
1109 \\ b,1109 \\ b,
1110 \\ c,1110 \\ c,
...@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1114 \\pub const e = @enumToInt(enum_unnamed_2.e);1114 \\pub const e = @enumToInt(enum_unnamed_2.e);
1115 \\pub const f = @enumToInt(enum_unnamed_2.f);1115 \\pub const f = @enumToInt(enum_unnamed_2.f);
1116 \\pub const g = @enumToInt(enum_unnamed_2.g);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 \\ e = 0,1118 \\ e = 0,
1119 \\ f = 4,1119 \\ f = 4,
1120 \\ g = 5,1120 \\ g = 5,
...@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1124 \\pub const i = @enumToInt(enum_unnamed_3.i);1124 \\pub const i = @enumToInt(enum_unnamed_3.i);
1125 \\pub const j = @enumToInt(enum_unnamed_3.j);1125 \\pub const j = @enumToInt(enum_unnamed_3.j);
1126 \\pub const k = @enumToInt(enum_unnamed_3.k);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 \\ i,1128 \\ i,
1129 \\ j,1129 \\ j,
1130 \\ k,1130 \\ k,
...@@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1137 \\pub const n = @enumToInt(enum_i.n);1137 \\pub const n = @enumToInt(enum_i.n);
1138 \\pub const o = @enumToInt(enum_i.o);1138 \\pub const o = @enumToInt(enum_i.o);
1139 \\pub const p = @enumToInt(enum_i.p);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 \\ n,1141 \\ n,
1142 \\ o,1142 \\ o,
1143 \\ p,1143 \\ p,
...@@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1569 , &[_][]const u8{1569 , &[_][]const u8{
1570 \\pub const One = @enumToInt(enum_unnamed_1.One);1570 \\pub const One = @enumToInt(enum_unnamed_1.One);
1571 \\pub const Two = @enumToInt(enum_unnamed_1.Two);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 \\ One,1573 \\ One,
1574 \\ Two,1574 \\ Two,
1575 \\ _,1575 \\ _,
...@@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1672 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);1672 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1673 \\}1673 \\}
1674 , &[_][]const u8{1674 , &[_][]const u8{
1675 \\pub const enum_Foo = extern enum {1675 \\pub const enum_Foo = extern enum(c_uint) {
1676 \\ A,1676 \\ A,
1677 \\ B,1677 \\ B,
1678 \\ C,1678 \\ C,
...@@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1718 \\ y: c_int,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 \\ A,1722 \\ A,
1723 \\ B,1723 \\ B,
1724 \\ _,1724 \\ _,
...@@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1982 \\ return 4;1982 \\ return 4;
1983 \\}1983 \\}
1984 , &[_][]const u8{1984 , &[_][]const u8{
1985 \\pub const enum_SomeEnum = extern enum {1985 \\pub const enum_SomeEnum = extern enum(c_uint) {
1986 \\ A,1986 \\ A,
1987 \\ B,1987 \\ B,
1988 \\ C,1988 \\ C,
...@@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2424 \\pub const FooA = @enumToInt(enum_Foo.A);2424 \\pub const FooA = @enumToInt(enum_Foo.A);
2425 \\pub const FooB = @enumToInt(enum_Foo.B);2425 \\pub const FooB = @enumToInt(enum_Foo.B);
2426 \\pub const Foo1 = @enumToInt(enum_Foo.@"1");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 \\ A = 2,2428 \\ A = 2,
2429 \\ B = 5,2429 \\ B = 5,
2430 \\ @"1" = 6,2430 \\ @"1" = 6,