authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-09-20 16:10:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-09-20 16:10:34-04:00
logb97bfc3ecba9655cdd989add13a7582272659268
treeaf3c8902db85adfd71995b7e3d49c3f51a17aafa
parent158225a2038e304cf5e8effa2f9e9624636b0d59

fix error when switch prong has implicit cast

closes #194

6 files changed, 243 insertions(+), 14 deletions(-)

src/analyze.cpp+5-3
...@@ -2540,8 +2540,8 @@ static const char *err_container_init_syntax_name(ContainerInitKind kind) {...@@ -2540,8 +2540,8 @@ static const char *err_container_init_syntax_name(ContainerInitKind kind) {
2540 zig_unreachable();2540 zig_unreachable();
2541}2541}
25422542
2543static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2543static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import,
2544 AstNode *node)2544 BlockContext *context, AstNode *node)
2545{2545{
2546 assert(node->type == NodeTypeContainerInitExpr);2546 assert(node->type == NodeTypeContainerInitExpr);
25472547
...@@ -6279,13 +6279,15 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -6279,13 +6279,15 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
6279 BlockContext *child_context = prong_node->data.switch_prong.block_context;6279 BlockContext *child_context = prong_node->data.switch_prong.block_context;
6280 child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);6280 child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
62816281
6282 peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
6283 if (child_context->codegen_excluded) {6282 if (child_context->codegen_excluded) {
6284 peer_types[prong_i] = g->builtin_types.entry_unreachable;6283 peer_types[prong_i] = g->builtin_types.entry_unreachable;
6285 } else {6284 } else {
6286 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,6285 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
6287 prong_node->data.switch_prong.expr);6286 prong_node->data.switch_prong.expr);
6288 }6287 }
6288 // This must go after the analyze_expression for
6289 // prong_node->data.switch_prong.expr because of AST rewriting.
6290 peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
6289 }6291 }
62906292
6291 if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {6293 if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
std/debug.zig+210-9
...@@ -3,6 +3,7 @@ const io = @import("io.zig");...@@ -3,6 +3,7 @@ const io = @import("io.zig");
3const os = @import("os.zig");3const os = @import("os.zig");
4const elf = @import("elf.zig");4const elf = @import("elf.zig");
5const DW = @import("dwarf.zig");5const DW = @import("dwarf.zig");
6const List = @import("list.zig").List;
67
7pub error MissingDebugInfo;8pub error MissingDebugInfo;
8pub error InvalidDebugInfo;9pub error InvalidDebugInfo;
...@@ -29,6 +30,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {...@@ -29,6 +30,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
2930
30 st.aranges = %return st.elf.findSection(".debug_aranges");31 st.aranges = %return st.elf.findSection(".debug_aranges");
31 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;32 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
33 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
3234
33 var maybe_fp: ?&const u8 = @frameAddress();35 var maybe_fp: ?&const u8 = @frameAddress();
34 while (true) {36 while (true) {
...@@ -62,6 +64,140 @@ struct ElfStackTrace {...@@ -62,6 +64,140 @@ struct ElfStackTrace {
62 elf: elf.Elf,64 elf: elf.Elf,
63 aranges: ?&elf.SectionHeader,65 aranges: ?&elf.SectionHeader,
64 debug_info: &elf.SectionHeader,66 debug_info: &elf.SectionHeader,
67 debug_abbrev: &elf.SectionHeader,
68}
69
70enum FormValue {
71 Address: u64,
72 Block: []u8,
73 Const: Constant,
74 ExprLoc: []u8,
75 Flag: bool,
76 SecOffset: u64,
77 Ref: []u8,
78 RefAddr: u64,
79 RefSig8: u64,
80 String: []u8,
81 StrPtr: u64,
82}
83
84struct Constant {
85 payload: []u8,
86 signed: bool,
87}
88
89
90fn readAllocBytes(in_stream: &io.InStream, size: usize) -> %[]u8 {
91 const buf = %return global_allocator.alloc(u8, size);
92 %defer global_allocator.free(u8, buf);
93 %return in_stream.read(buf);
94 return buf;
95}
96
97fn parseFormValueBlockLen(in_stream: &io.InStream, size: usize) -> %FormValue {
98 const buf = %return readAllocBytes(in_stream, size);
99 return FormValue.Block { buf };
100}
101
102fn parseFormValueBlock(in_stream: &io.InStream, inline T: type) -> %FormValue {
103 const block_len = %return in_stream.readIntLe(T);
104 return parseFormValueBlockLen(in_stream, block_len);
105}
106
107fn parseFormValueConstantLen(in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
108 const buf = %return readAllocBytes(in_stream, size);
109 return FormValue.Const { Constant {
110 .signed = signed,
111 .payload = buf,
112 }};
113}
114
115fn parseFormValueConstant(in_stream: &io.InStream, signed: bool, inline T: type) -> %FormValue {
116 const block_len = %return in_stream.readIntLe(T);
117 return parseFormValueConstantLen(in_stream, signed, block_len);
118}
119
120fn parseFormValueAddrSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
121 return if (is_64) {
122 %return in_stream.readIntLe(u64)
123 } else {
124 u64(%return in_stream.readIntLe(u32))
125 };
126}
127
128fn parseFormValueRefLen(in_stream: &io.InStream, size: usize) -> %FormValue {
129 const buf = %return readAllocBytes(in_stream, size);
130 return FormValue.Ref { buf };
131}
132
133fn parseFormValueRef(in_stream: &io.InStream, inline T: type) -> %FormValue {
134 const block_len = %return in_stream.readIntLe(T);
135 return parseFormValueRefLen(in_stream, block_len);
136}
137
138fn parseFormValue(in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
139 return switch (form_id) {
140 DW.FORM_addr => FormValue.Address {
141 %return parseFormValueAddrSize(in_stream, is_64)
142 },
143 DW.FORM_block1 => parseFormValueBlock(in_stream, u8),
144 DW.FORM_block2 => parseFormValueBlock(in_stream, u16),
145 DW.FORM_block4 => parseFormValueBlock(in_stream, u32),
146 DW.FORM_block => {
147 const block_len = %return readULeb128(in_stream);
148 parseFormValueBlockLen(in_stream, block_len)
149 },
150 DW.FORM_data1 => parseFormValueConstant(in_stream, false, u8),
151 DW.FORM_data2 => parseFormValueConstant(in_stream, false, u16),
152 DW.FORM_data4 => parseFormValueConstant(in_stream, false, u32),
153 DW.FORM_data8 => parseFormValueConstant(in_stream, false, u64),
154 DW.FORM_udata, DW.FORM_sdata => {
155 const block_len = %return readULeb128(in_stream);
156 const signed = form_id == DW.FORM_sdata;
157 parseFormValueConstantLen(in_stream, signed, block_len)
158 },
159 DW.FORM_exprloc => {
160 const size = %return readULeb128(in_stream);
161 const buf = %return readAllocBytes(in_stream, size);
162 return FormValue.ExprLoc { buf };
163 },
164 DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 },
165 DW.FORM_flag_present => FormValue.Flag { true },
166 DW.FORM_sec_offset => FormValue.SecOffset {
167 %return parseFormValueAddrSize(in_stream, is_64)
168 },
169
170 DW.FORM_ref1 => parseFormValueRef(in_stream, u8),
171 DW.FORM_ref2 => parseFormValueRef(in_stream, u16),
172 DW.FORM_ref4 => parseFormValueRef(in_stream, u32),
173 DW.FORM_ref8 => parseFormValueRef(in_stream, u64),
174 DW.FORM_ref_udata => {
175 const ref_len = %return readULeb128(in_stream);
176 parseFormValueRefLen(in_stream, ref_len)
177 },
178
179 DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueAddrSize(in_stream, is_64) },
180 DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) },
181
182 DW.FORM_string => {
183 var buf: List(u8) = undefined;
184 buf.init(&global_allocator);
185 while (true) {
186 const byte = %return in_stream.readByte();
187 if (byte == 0)
188 break;
189 %return buf.append(byte);
190 }
191
192 FormValue.String { buf.items }
193 },
194 DW.FORM_strp => FormValue.StrPtr { %return parseFormValueAddrSize(in_stream, is_64) },
195 DW.FORM_indirect => {
196 const child_form_id = %return readULeb128(in_stream);
197 parseFormValue(in_stream, child_form_id, is_64)
198 },
199 else => return error.InvalidDebugInfo,
200 }
65}201}
66202
67fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {203fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {
...@@ -72,8 +208,78 @@ fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {...@@ -72,8 +208,78 @@ fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {
72 %return st.elf.seekToSection(st.debug_info);208 %return st.elf.seekToSection(st.debug_info);
73209
74 while (true) {210 while (true) {
75 const tag_id = %return st.self_exe_stream.readByte();211 var is_64: bool = undefined;
76 // TODO iterate until we find the relevant compile unit212 const unit_length = %return readInitialLength(&st.self_exe_stream, &is_64);
213
214 const version = %return st.self_exe_stream.readInt(st.elf.is_big_endian, u16);
215 if (version != 4) return error.InvalidDebugInfo;
216
217 const debug_abbrev_offset = if (is_64) {
218 %return st.self_exe_stream.readInt(st.elf.is_big_endian, u64)
219 } else {
220 %return st.self_exe_stream.readInt(st.elf.is_big_endian, u32)
221 };
222
223 const address_size = %return st.self_exe_stream.readByte();
224 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
225
226 const abbrev_tag_id = %return st.self_exe_stream.readByte();
227
228
229 }
230}
231
232fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
233 const first_32_bits = %return in_stream.readIntLe(u32);
234 *is_64 = (first_32_bits == 0xffffffff);
235 return if (*is_64) {
236 %return in_stream.readIntLe(u64)
237 } else {
238 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
239 u64(first_32_bits)
240 };
241}
242
243fn readULeb128(in_stream: &io.InStream) -> %u64 {
244 var result: u64 = 0;
245 var shift: u64 = 0;
246
247 while (true) {
248 const byte = %return in_stream.readByte();
249 var operand: u64 = undefined;
250
251 if (@shlWithOverflow(u64, byte & 0b01111111, shift, &operand))
252 return error.InvalidDebugInfo;
253
254 result |= operand;
255
256 if ((byte & 0b10000000) == 0)
257 return result;
258
259 shift += 7;
260 }
261}
262
263fn readILeb128(in_stream: &io.InStream) -> %i64 {
264 var result: i64 = 0;
265 var shift: i64 = 0;
266
267 while (true) {
268 const byte = %return in_stream.readByte();
269 var operand: i64 = undefined;
270
271 if (@shlWithOverflow(i64, byte & 0b01111111, shift, &operand))
272 return error.InvalidDebugInfo;
273
274 result |= operand;
275 shift += 7;
276
277 if ((byte & 0b10000000) == 0) {
278 if (shift < @sizeOf(i64) * 8 && (byte & 0b01000000) != 0)
279 result |= -(i64(1) << shift);
280
281 return result;
282 }
77 }283 }
78}284}
79285
...@@ -84,13 +290,8 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {...@@ -84,13 +290,8 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
84 %return st.elf.seekToSection(aranges);290 %return st.elf.seekToSection(aranges);
85291
86 const first_32_bits = %return st.self_exe_stream.readIntLe(u32);292 const first_32_bits = %return st.self_exe_stream.readIntLe(u32);
87 const is_64 = (first_32_bits == 0xffffffff);293 var is_64: bool = undefined;
88 const unit_length = if (is_64) {294 const unit_length = %return readInitialLength(&st.self_exe_stream, &is_64);
89 %return st.self_exe_stream.readIntLe(u64)
90 } else {
91 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
92 first_32_bits
93 };
94 var unit_index: u64 = 0;295 var unit_index: u64 = 0;
95296
96 while (unit_index < unit_length) {297 while (unit_index < unit_length) {
std/dwarf.zig-2
...@@ -127,8 +127,6 @@ pub const FORM_ref4 = 0x13;...@@ -127,8 +127,6 @@ pub const FORM_ref4 = 0x13;
127pub const FORM_ref8 = 0x14;127pub const FORM_ref8 = 0x14;
128pub const FORM_ref_udata = 0x15;128pub const FORM_ref_udata = 0x15;
129pub const FORM_indirect = 0x16;129pub const FORM_indirect = 0x16;
130
131// DWARF 4.
132pub const FORM_sec_offset = 0x17;130pub const FORM_sec_offset = 0x17;
133pub const FORM_exprloc = 0x18;131pub const FORM_exprloc = 0x18;
134pub const FORM_flag_present = 0x19;132pub const FORM_flag_present = 0x19;
std/mem.zig+1
...@@ -35,6 +35,7 @@ pub struct Allocator {...@@ -35,6 +35,7 @@ pub struct Allocator {
35 ([]T)(%return self.reallocFn(self, ([]u8)(old_mem), byte_count))35 ([]T)(%return self.reallocFn(self, ([]u8)(old_mem), byte_count))
36 }36 }
3737
38 // TODO mem: []var and get rid of 2nd param
38 fn free(self: &Allocator, inline T: type, mem: []T) {39 fn free(self: &Allocator, inline T: type, mem: []T) {
39 self.freeFn(self, ([]u8)(mem));40 self.freeFn(self, ([]u8)(mem));
40 }41 }
test/cases/switch_prong_implicit_cast.zig created+26
...@@ -0,0 +1,26 @@
1const assert = @import("std").debug.assert;
2
3enum FormValue {
4 One,
5 Two: bool,
6}
7
8error Whatever;
9
10#static_eval_enable(false)
11fn foo(id: u64) -> %FormValue {
12 switch (id) {
13 2 => FormValue.Two { true },
14 1 => FormValue.One,
15 else => return error.Whatever,
16 }
17}
18
19#attribute("test")
20fn switchProngImplicitCast() {
21 const result = switch (%%foo(2)) {
22 One => false,
23 Two => |x| x,
24 };
25 assert(result);
26}
test/self_hosted.zig+1
...@@ -11,6 +11,7 @@ const test_maybe_return = @import("cases/maybe_return.zig");...@@ -11,6 +11,7 @@ const test_maybe_return = @import("cases/maybe_return.zig");
11const test_max_value_type = @import("cases/max_value_type.zig");11const test_max_value_type = @import("cases/max_value_type.zig");
12const test_var_params = @import("cases/var_params.zig");12const test_var_params = @import("cases/var_params.zig");
13const test_const_slice_child = @import("cases/const_slice_child.zig");13const test_const_slice_child = @import("cases/const_slice_child.zig");
14const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
1415
15// normal comment16// normal comment
16/// this is a documentation comment17/// this is a documentation comment