authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-09 13:49:58-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-09 13:49:58-05:00
loge7bf8f3f04efc280a76a3a38b4e6d470d279e41a
tree2e2398667f04fa46d5de7ae4e686fe1088bf264b
parent1fb308ceeea0259ad021d67945ea5adc10960a85

fix compiler crash switching on global error with no else


4 files changed, 38 insertions(+), 19 deletions(-)

src/ir.cpp+12-6
...@@ -15663,13 +15663,19 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -15663,13 +15663,19 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
15663 field_prev_uses[start_index] = start_value->source_node;15663 field_prev_uses[start_index] = start_value->source_node;
15664 }15664 }
15665 if (!instruction->have_else_prong) {15665 if (!instruction->have_else_prong) {
15666 for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) {15666 if (type_is_global_error_set(switch_type)) {
15667 ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i];15667 ir_add_error(ira, &instruction->base,
15668 buf_sprintf("else prong required when switching on type 'error'"));
15669 return ira->codegen->builtin_types.entry_invalid;
15670 } else {
15671 for (uint32_t i = 0; i < switch_type->data.error_set.err_count; i += 1) {
15672 ErrorTableEntry *err_entry = switch_type->data.error_set.errors[i];
1566815673
15669 AstNode *prev_node = field_prev_uses[err_entry->value];15674 AstNode *prev_node = field_prev_uses[err_entry->value];
15670 if (prev_node == nullptr) {15675 if (prev_node == nullptr) {
15671 ir_add_error(ira, &instruction->base,15676 ir_add_error(ira, &instruction->base,
15672 buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name)));15677 buf_sprintf("error.%s not handled in switch", buf_ptr(&err_entry->name)));
15678 }
15673 }15679 }
15674 }15680 }
15675 }15681 }
std/io.zig+1-1
...@@ -499,7 +499,7 @@ pub fn OutStream(comptime Error: type) type {...@@ -499,7 +499,7 @@ pub fn OutStream(comptime Error: type) type {
499 writeFn: fn(self: &Self, bytes: []const u8) Error!void,499 writeFn: fn(self: &Self, bytes: []const u8) Error!void,
500500
501 pub fn print(self: &Self, comptime format: []const u8, args: ...) !void {501 pub fn print(self: &Self, comptime format: []const u8, args: ...) !void {
502 return std.fmt.format(self, error, self.writeFn, format, args);502 return std.fmt.format(self, Error, self.writeFn, format, args);
503 }503 }
504504
505 pub fn write(self: &Self, bytes: []const u8) !void {505 pub fn write(self: &Self, bytes: []const u8) !void {
std/zig/parser.zig+13-12
...@@ -133,7 +133,6 @@ pub const Parser = struct {...@@ -133,7 +133,6 @@ pub const Parser = struct {
133 Token.Id.Eof => return Tree {.root_node = root_node},133 Token.Id.Eof => return Tree {.root_node = root_node},
134 else => {134 else => {
135 self.putBackToken(token);135 self.putBackToken(token);
136 // TODO shouldn't need this cast
137 stack.append(State { .TopLevelExtern = null }) catch unreachable;136 stack.append(State { .TopLevelExtern = null }) catch unreachable;
138 continue;137 continue;
139 },138 },
...@@ -707,7 +706,7 @@ pub const Parser = struct {...@@ -707,7 +706,7 @@ pub const Parser = struct {
707 return node;706 return node;
708 }707 }
709708
710 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) error {709 fn parseError(self: &Parser, token: &const Token, comptime fmt: []const u8, args: ...) (error{ParseError}) {
711 const loc = self.tokenizer.getTokenLocation(token);710 const loc = self.tokenizer.getTokenLocation(token);
712 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);711 warn("{}:{}:{}: error: " ++ fmt ++ "\n", self.source_file_name, loc.line + 1, loc.column + 1, args);
713 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);712 warn("{}\n", self.tokenizer.buffer[loc.line_start..loc.line_end]);
...@@ -1082,16 +1081,18 @@ fn testCanonical(source: []const u8) !void {...@@ -1082,16 +1081,18 @@ fn testCanonical(source: []const u8) !void {
1082 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);1081 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1083 if (testParse(source, &failing_allocator.allocator)) |_| {1082 if (testParse(source, &failing_allocator.allocator)) |_| {
1084 return error.NondeterministicMemoryUsage;1083 return error.NondeterministicMemoryUsage;
1085 } else |err| {1084 } else |err| switch (err) {
1086 assert(err == error.OutOfMemory);1085 error.OutOfMemory => {
1087 // TODO make this pass1086 // TODO make this pass
1088 //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {1087 //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
1089 // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",1088 // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
1090 // fail_index, needed_alloc_count,1089 // fail_index, needed_alloc_count,
1091 // failing_allocator.allocated_bytes, failing_allocator.freed_bytes,1090 // failing_allocator.allocated_bytes, failing_allocator.freed_bytes,
1092 // failing_allocator.index, failing_allocator.deallocations);1091 // failing_allocator.index, failing_allocator.deallocations);
1093 // return error.MemoryLeakDetected;1092 // return error.MemoryLeakDetected;
1094 //}1093 //}
1094 },
1095 error.ParseError => @panic("test failed"),
1095 }1096 }
1096 }1097 }
1097}1098}
test/compile_errors.zig+12
...@@ -1,6 +1,18 @@...@@ -1,6 +1,18 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) void {3pub fn addCases(cases: &tests.CompileErrorContext) void {
4 cases.add("no else prong on switch on global error set",
5 \\export fn entry() void {
6 \\ foo(error.A);
7 \\}
8 \\fn foo(a: error) void {
9 \\ switch (a) {
10 \\ error.A => {},
11 \\ }
12 \\}
13 ,
14 ".tmp_source.zig:5:5: error: else prong required when switching on type 'error'");
15
4 cases.add("inferred error set with no returned error",16 cases.add("inferred error set with no returned error",
5 \\export fn entry() void {17 \\export fn entry() void {
6 \\ foo() catch unreachable;18 \\ foo() catch unreachable;