authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-07 00:39:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-07 00:39:23-07:00
log13f04e3012b6b2eee141923f9780fce55f7a999d
treefd8d164d7926d76a1e967b89283322ee6ad88bb0
parentd481acc7dbebb5501b5fef608ee1f6b13c442c6a

stage2: implement `@panic` and beginnigs of inferred error sets

* ZIR: add two instructions: - ret_err_value_code - ret_err_value * AstGen: add countDefers and utilize it to emit more efficient ZIR for return expressions in the presence of defers. * AstGen: implement |err| payloads for `errdefer` syntax. - There is not an "unused capture" error for it yet. * AstGen: `return error.Foo` syntax gets a hot path in return expressions, using the new ZIR instructions. This also is part of implementing inferred error sets, since we need to tell Sema to add an error value to the inferred error set before it gets coerced. * Sema: implement `@setCold`. - Implement `@setCold` support for C backend. * `@panic` and regular safety panics such as `unreachable` now properly invoke `std.builtin.panic`. * C backend: improve pointer and function value rendering. * C linker: fix redundant typedefs. * Add Type.error_set_inferred. * Fix Value.format for enum_literal, enum_field_index, bytes. * Remove the C backend test that checks for identical text I measured a 14% reduction in Total ZIR Bytes from master branch for std/os.zig.

11 files changed, 650 insertions(+), 182 deletions(-)

src/AstGen.zig+124-17
...@@ -1860,7 +1860,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod...@@ -1860,7 +1860,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
1860 }1860 }
1861 }1861 }
18621862
1863 try genDefers(gz, parent_scope, scope, .none);1863 try genDefers(gz, parent_scope, scope, .normal_only);
1864 try checkUsed(gz, parent_scope, scope);1864 try checkUsed(gz, parent_scope, scope);
1865}1865}
18661866
...@@ -2102,6 +2102,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2102,6 +2102,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2102 .@"resume",2102 .@"resume",
2103 .@"await",2103 .@"await",
2104 .await_nosuspend,2104 .await_nosuspend,
2105 .ret_err_value_code,
2105 .extended,2106 .extended,
2106 => break :b false,2107 => break :b false,
21072108
...@@ -2113,6 +2114,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2113,6 +2114,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2113 .compile_error,2114 .compile_error,
2114 .ret_node,2115 .ret_node,
2115 .ret_coerce,2116 .ret_coerce,
2117 .ret_err_value,
2116 .@"unreachable",2118 .@"unreachable",
2117 .repeat,2119 .repeat,
2118 .repeat_inline,2120 .repeat_inline,
...@@ -2162,13 +2164,63 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -2162,13 +2164,63 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
2162 return noreturn_src_node;2164 return noreturn_src_node;
2163}2165}
21642166
2167fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct {
2168 have_any: bool,
2169 have_normal: bool,
2170 have_err: bool,
2171 need_err_code: bool,
2172} {
2173 const tree = astgen.tree;
2174 const node_datas = tree.nodes.items(.data);
2175
2176 var have_normal = false;
2177 var have_err = false;
2178 var need_err_code = false;
2179 var scope = inner_scope;
2180 while (scope != outer_scope) {
2181 switch (scope.tag) {
2182 .gen_zir => scope = scope.cast(GenZir).?.parent,
2183 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2184 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2185 .defer_normal => {
2186 const defer_scope = scope.cast(Scope.Defer).?;
2187 scope = defer_scope.parent;
2188
2189 have_normal = true;
2190 },
2191 .defer_error => {
2192 const defer_scope = scope.cast(Scope.Defer).?;
2193 scope = defer_scope.parent;
2194
2195 have_err = true;
2196
2197 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0;
2198 need_err_code = need_err_code or have_err_payload;
2199 },
2200 .namespace => unreachable,
2201 .top => unreachable,
2202 }
2203 }
2204 return .{
2205 .have_any = have_normal or have_err,
2206 .have_normal = have_normal,
2207 .have_err = have_err,
2208 .need_err_code = need_err_code,
2209 };
2210}
2211
2212const DefersToEmit = union(enum) {
2213 both: Zir.Inst.Ref, // err code
2214 both_sans_err,
2215 normal_only,
2216};
2217
2165fn genDefers(2218fn genDefers(
2166 gz: *GenZir,2219 gz: *GenZir,
2167 outer_scope: *Scope,2220 outer_scope: *Scope,
2168 inner_scope: *Scope,2221 inner_scope: *Scope,
2169 err_code: Zir.Inst.Ref,2222 which_ones: DefersToEmit,
2170) InnerError!void {2223) InnerError!void {
2171 _ = err_code;
2172 const astgen = gz.astgen;2224 const astgen = gz.astgen;
2173 const tree = astgen.tree;2225 const tree = astgen.tree;
2174 const node_datas = tree.nodes.items(.data);2226 const node_datas = tree.nodes.items(.data);
...@@ -2191,12 +2243,37 @@ fn genDefers(...@@ -2191,12 +2243,37 @@ fn genDefers(
2191 .defer_error => {2243 .defer_error => {
2192 const defer_scope = scope.cast(Scope.Defer).?;2244 const defer_scope = scope.cast(Scope.Defer).?;
2193 scope = defer_scope.parent;2245 scope = defer_scope.parent;
2194 if (err_code == .none) continue;2246 switch (which_ones) {
2195 const expr_node = node_datas[defer_scope.defer_node].rhs;2247 .both_sans_err => {
2196 const prev_in_defer = gz.in_defer;2248 const expr_node = node_datas[defer_scope.defer_node].rhs;
2197 gz.in_defer = true;2249 const prev_in_defer = gz.in_defer;
2198 defer gz.in_defer = prev_in_defer;2250 gz.in_defer = true;
2199 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);2251 defer gz.in_defer = prev_in_defer;
2252 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
2253 },
2254 .both => |err_code| {
2255 const expr_node = node_datas[defer_scope.defer_node].rhs;
2256 const payload_token = node_datas[defer_scope.defer_node].lhs;
2257 const prev_in_defer = gz.in_defer;
2258 gz.in_defer = true;
2259 defer gz.in_defer = prev_in_defer;
2260 var local_val_scope: Scope.LocalVal = undefined;
2261 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {
2262 const ident_name = try astgen.identAsString(payload_token);
2263 local_val_scope = .{
2264 .parent = defer_scope.parent,
2265 .gen_zir = gz,
2266 .name = ident_name,
2267 .inst = err_code,
2268 .token_src = payload_token,
2269 .id_cat = .@"capture",
2270 };
2271 break :blk &local_val_scope.base;
2272 };
2273 _ = try unusedResultExpr(gz, sub_scope, expr_node);
2274 },
2275 .normal_only => continue,
2276 }
2200 },2277 },
2201 .namespace => unreachable,2278 .namespace => unreachable,
2202 .top => unreachable,2279 .top => unreachable,
...@@ -4564,7 +4641,7 @@ fn tryExpr(...@@ -4564,7 +4641,7 @@ fn tryExpr(
4564 defer then_scope.instructions.deinit(astgen.gpa);4641 defer then_scope.instructions.deinit(astgen.gpa);
45654642
4566 const err_code = try then_scope.addUnNode(err_ops[1], operand, node);4643 const err_code = try then_scope.addUnNode(err_ops[1], operand, node);
4567 try genDefers(&then_scope, &fn_block.base, scope, err_code);4644 try genDefers(&then_scope, &fn_block.base, scope, .{ .both = err_code });
4568 const then_result = try then_scope.addUnNode(.ret_node, err_code, node);4645 const then_result = try then_scope.addUnNode(.ret_node, err_code, node);
45694646
4570 var else_scope = parent_gz.makeSubBlock(scope);4647 var else_scope = parent_gz.makeSubBlock(scope);
...@@ -6090,17 +6167,37 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6090,17 +6167,37 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6090 const astgen = gz.astgen;6167 const astgen = gz.astgen;
6091 const tree = astgen.tree;6168 const tree = astgen.tree;
6092 const node_datas = tree.nodes.items(.data);6169 const node_datas = tree.nodes.items(.data);
6170 const node_tags = tree.nodes.items(.tag);
60936171
6094 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});6172 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
60956173
6174 const defer_outer = &astgen.fn_block.?.base;
6175
6096 const operand_node = node_datas[node].lhs;6176 const operand_node = node_datas[node].lhs;
6097 if (operand_node == 0) {6177 if (operand_node == 0) {
6098 // Returning a void value; skip error defers.6178 // Returning a void value; skip error defers.
6099 try genDefers(gz, &astgen.fn_block.?.base, scope, .none);6179 try genDefers(gz, defer_outer, scope, .normal_only);
6100 _ = try gz.addUnNode(.ret_node, .void_value, node);6180 _ = try gz.addUnNode(.ret_node, .void_value, node);
6101 return Zir.Inst.Ref.unreachable_value;6181 return Zir.Inst.Ref.unreachable_value;
6102 }6182 }
61036183
6184 if (node_tags[operand_node] == .error_value) {
6185 // Hot path for `return error.Foo`. This bypasses result location logic as well as logic
6186 // for detecting whether to add something to the function's inferred error set.
6187 const ident_token = node_datas[operand_node].rhs;
6188 const err_name_str_index = try astgen.identAsString(ident_token);
6189 const defer_counts = countDefers(astgen, defer_outer, scope);
6190 if (!defer_counts.need_err_code) {
6191 try genDefers(gz, defer_outer, scope, .both_sans_err);
6192 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
6193 return Zir.Inst.Ref.unreachable_value;
6194 }
6195 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
6196 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6197 _ = try gz.addUnNode(.ret_node, err_code, node);
6198 return Zir.Inst.Ref.unreachable_value;
6199 }
6200
6104 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{6201 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{
6105 .ptr = try gz.addNodeExtended(.ret_ptr, node),6202 .ptr = try gz.addNodeExtended(.ret_ptr, node),
6106 } else .{6203 } else .{
...@@ -6111,31 +6208,41 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6111,31 +6208,41 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6111 switch (nodeMayEvalToError(tree, operand_node)) {6208 switch (nodeMayEvalToError(tree, operand_node)) {
6112 .never => {6209 .never => {
6113 // Returning a value that cannot be an error; skip error defers.6210 // Returning a value that cannot be an error; skip error defers.
6114 try genDefers(gz, &astgen.fn_block.?.base, scope, .none);6211 try genDefers(gz, defer_outer, scope, .normal_only);
6115 _ = try gz.addUnNode(.ret_node, operand, node);6212 _ = try gz.addUnNode(.ret_node, operand, node);
6116 return Zir.Inst.Ref.unreachable_value;6213 return Zir.Inst.Ref.unreachable_value;
6117 },6214 },
6118 .always => {6215 .always => {
6119 // Value is always an error. Emit both error defers and regular defers.6216 // Value is always an error. Emit both error defers and regular defers.
6120 const err_code = try gz.addUnNode(.err_union_code, operand, node);6217 const err_code = try gz.addUnNode(.err_union_code, operand, node);
6121 try genDefers(gz, &astgen.fn_block.?.base, scope, err_code);6218 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6122 _ = try gz.addUnNode(.ret_node, operand, node);6219 _ = try gz.addUnNode(.ret_node, operand, node);
6123 return Zir.Inst.Ref.unreachable_value;6220 return Zir.Inst.Ref.unreachable_value;
6124 },6221 },
6125 .maybe => {6222 .maybe => {
6223 const defer_counts = countDefers(astgen, defer_outer, scope);
6224 if (!defer_counts.have_err) {
6225 // Only regular defers; no branch needed.
6226 try genDefers(gz, defer_outer, scope, .normal_only);
6227 _ = try gz.addUnNode(.ret_node, operand, node);
6228 return Zir.Inst.Ref.unreachable_value;
6229 }
6230
6126 // Emit conditional branch for generating errdefers.6231 // Emit conditional branch for generating errdefers.
6127 const is_err = try gz.addUnNode(.is_err, operand, node);6232 const is_err = try gz.addUnNode(.is_err, operand, node);
6128 const condbr = try gz.addCondBr(.condbr, node);6233 const condbr = try gz.addCondBr(.condbr, node);
61296234
6130 var then_scope = gz.makeSubBlock(scope);6235 var then_scope = gz.makeSubBlock(scope);
6131 defer then_scope.instructions.deinit(astgen.gpa);6236 defer then_scope.instructions.deinit(astgen.gpa);
6132 const err_code = try then_scope.addUnNode(.err_union_code, operand, node);6237 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
6133 try genDefers(&then_scope, &astgen.fn_block.?.base, scope, err_code);6238 .both = try then_scope.addUnNode(.err_union_code, operand, node),
6239 };
6240 try genDefers(&then_scope, defer_outer, scope, which_ones);
6134 _ = try then_scope.addUnNode(.ret_node, operand, node);6241 _ = try then_scope.addUnNode(.ret_node, operand, node);
61356242
6136 var else_scope = gz.makeSubBlock(scope);6243 var else_scope = gz.makeSubBlock(scope);
6137 defer else_scope.instructions.deinit(astgen.gpa);6244 defer else_scope.instructions.deinit(astgen.gpa);
6138 try genDefers(&else_scope, &astgen.fn_block.?.base, scope, .none);6245 try genDefers(&else_scope, defer_outer, scope, .normal_only);
6139 _ = try else_scope.addUnNode(.ret_node, operand, node);6246 _ = try else_scope.addUnNode(.ret_node, operand, node);
61406247
6141 try setCondBrPayload(condbr, is_err, &then_scope, &else_scope);6248 try setCondBrPayload(condbr, is_err, &then_scope, &else_scope);
...@@ -6885,7 +6992,7 @@ fn builtinCall(...@@ -6885,7 +6992,7 @@ fn builtinCall(
6885 .field => {6992 .field => {
6886 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);6993 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
6887 if (rl == .ref) {6994 if (rl == .ref) {
6888 return try gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{6995 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
6889 .lhs = try expr(gz, scope, .ref, params[0]),6996 .lhs = try expr(gz, scope, .ref, params[0]),
6890 .field_name = field_name,6997 .field_name = field_name,
6891 });6998 });
src/Module.zig+4
...@@ -755,6 +755,7 @@ pub const Fn = struct {...@@ -755,6 +755,7 @@ pub const Fn = struct {
755 rbrace_column: u16,755 rbrace_column: u16,
756756
757 state: Analysis,757 state: Analysis,
758 is_cold: bool = false,
758759
759 pub const Analysis = enum {760 pub const Analysis = enum {
760 queued,761 queued,
...@@ -3453,6 +3454,9 @@ pub fn clearDecl(...@@ -3453,6 +3454,9 @@ pub fn clearDecl(
3453 for (decl.dependencies.keys()) |dep| {3454 for (decl.dependencies.keys()) |dep| {
3454 dep.removeDependant(decl);3455 dep.removeDependant(decl);
3455 if (dep.dependants.count() == 0 and !dep.deletion_flag) {3456 if (dep.dependants.count() == 0 and !dep.deletion_flag) {
3457 log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{
3458 decl, decl.name, dep, dep.name,
3459 });
3456 // We don't recursively perform a deletion here, because during the update,3460 // We don't recursively perform a deletion here, because during the update,
3457 // another reference to it may turn up.3461 // another reference to it may turn up.
3458 dep.deletion_flag = true;3462 dep.deletion_flag = true;
src/Sema.zig+148-63
...@@ -244,6 +244,7 @@ pub fn analyzeBody(...@@ -244,6 +244,7 @@ pub fn analyzeBody(
244 .ptr_type => try sema.zirPtrType(block, inst),244 .ptr_type => try sema.zirPtrType(block, inst),
245 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),245 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
246 .ref => try sema.zirRef(block, inst),246 .ref => try sema.zirRef(block, inst),
247 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
247 .shl => try sema.zirShl(block, inst),248 .shl => try sema.zirShl(block, inst),
248 .shr => try sema.zirShr(block, inst),249 .shr => try sema.zirShr(block, inst),
249 .slice_end => try sema.zirSliceEnd(block, inst),250 .slice_end => try sema.zirSliceEnd(block, inst),
...@@ -380,8 +381,9 @@ pub fn analyzeBody(...@@ -380,8 +381,9 @@ pub fn analyzeBody(
380 .condbr => return sema.zirCondbr(block, inst),381 .condbr => return sema.zirCondbr(block, inst),
381 .@"break" => return sema.zirBreak(block, inst),382 .@"break" => return sema.zirBreak(block, inst),
382 .compile_error => return sema.zirCompileError(block, inst),383 .compile_error => return sema.zirCompileError(block, inst),
383 .ret_coerce => return sema.zirRetTok(block, inst, true),384 .ret_coerce => return sema.zirRetCoerce(block, inst, true),
384 .ret_node => return sema.zirRetNode(block, inst),385 .ret_node => return sema.zirRetNode(block, inst),
386 .ret_err_value => return sema.zirRetErrValue(block, inst),
385 .@"unreachable" => return sema.zirUnreachable(block, inst),387 .@"unreachable" => return sema.zirUnreachable(block, inst),
386 .repeat => return sema.zirRepeat(block, inst),388 .repeat => return sema.zirRepeat(block, inst),
387 .panic => return sema.zirPanic(block, inst),389 .panic => return sema.zirPanic(block, inst),
...@@ -587,6 +589,19 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In...@@ -587,6 +589,19 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
587 return sema.inst_map.get(@intCast(u32, i)).?;589 return sema.inst_map.get(@intCast(u32, i)).?;
588}590}
589591
592fn resolveConstBool(
593 sema: *Sema,
594 block: *Scope.Block,
595 src: LazySrcLoc,
596 zir_ref: Zir.Inst.Ref,
597) !bool {
598 const air_inst = try sema.resolveInst(zir_ref);
599 const wanted_type = Type.initTag(.bool);
600 const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
601 const val = try sema.resolveConstValue(block, src, coerced_inst);
602 return val.toBool();
603}
604
590fn resolveConstString(605fn resolveConstString(
591 sema: *Sema,606 sema: *Sema,
592 block: *Scope.Block,607 block: *Scope.Block,
...@@ -1754,8 +1769,9 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -1754,8 +1769,9 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
1754fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {1769fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
1755 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1770 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1756 const src: LazySrcLoc = inst_data.src();1771 const src: LazySrcLoc = inst_data.src();
1757 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{});1772 const msg_inst = try sema.resolveInst(inst_data.operand);
1758 //return always_noreturn;1773
1774 return sema.panicWithMsg(block, src, msg_inst);
1759}1775}
17601776
1761fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {1777fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
...@@ -2028,8 +2044,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inne...@@ -2028,8 +2044,10 @@ fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inne
20282044
2029fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2045fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
2030 const inst_data = sema.code.instructions.items(.data)[inst].un_node;2046 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2031 const src: LazySrcLoc = inst_data.src();2047 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2032 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{});2048 const is_cold = try sema.resolveConstBool(block, operand_src, inst_data.operand);
2049 const func = sema.func orelse return; // does nothing outside a function
2050 func.is_cold = is_cold;
2033}2051}
20342052
2035fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2053fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
...@@ -2041,11 +2059,7 @@ fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner...@@ -2041,11 +2059,7 @@ fn zirSetFloatMode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Inner
2041fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2059fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
2042 const inst_data = sema.code.instructions.items(.data)[inst].un_node;2060 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2043 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };2061 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
20442062 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand);
2045 const op = try sema.resolveInst(inst_data.operand);
2046 const op_coerced = try sema.coerce(block, Type.initTag(.bool), op, operand_src);
2047 const b = (try sema.resolveConstValue(block, operand_src, op_coerced)).toBool();
2048 block.want_safety = b;
2049}2063}
20502064
2051fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {2065fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
...@@ -2190,21 +2204,27 @@ fn zirCall(...@@ -2190,21 +2204,27 @@ fn zirCall(
2190 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);2204 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
2191 const args = sema.code.refSlice(extra.end, extra.data.args_len);2205 const args = sema.code.refSlice(extra.end, extra.data.args_len);
21922206
2193 return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);2207 const func = try sema.resolveInst(extra.data.callee);
2208 // TODO handle function calls of generic functions
2209 const resolved_args = try sema.arena.alloc(*Inst, args.len);
2210 for (args) |zir_arg, i| {
2211 // the args are already casted to the result of a param type instruction.
2212 resolved_args[i] = try sema.resolveInst(zir_arg);
2213 }
2214
2215 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args);
2194}2216}
21952217
2196fn analyzeCall(2218fn analyzeCall(
2197 sema: *Sema,2219 sema: *Sema,
2198 block: *Scope.Block,2220 block: *Scope.Block,
2199 zir_func: Zir.Inst.Ref,2221 func: *ir.Inst,
2200 func_src: LazySrcLoc,2222 func_src: LazySrcLoc,
2201 call_src: LazySrcLoc,2223 call_src: LazySrcLoc,
2202 modifier: std.builtin.CallOptions.Modifier,2224 modifier: std.builtin.CallOptions.Modifier,
2203 ensure_result_used: bool,2225 ensure_result_used: bool,
2204 zir_args: []const Zir.Inst.Ref,2226 args: []const *ir.Inst,
2205) InnerError!*ir.Inst {2227) InnerError!*ir.Inst {
2206 const func = try sema.resolveInst(zir_func);
2207
2208 if (func.ty.zigTypeTag() != .Fn)2228 if (func.ty.zigTypeTag() != .Fn)
2209 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});2229 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
22102230
...@@ -2221,22 +2241,22 @@ fn analyzeCall(...@@ -2221,22 +2241,22 @@ fn analyzeCall(
2221 const fn_params_len = func.ty.fnParamLen();2241 const fn_params_len = func.ty.fnParamLen();
2222 if (func.ty.fnIsVarArgs()) {2242 if (func.ty.fnIsVarArgs()) {
2223 assert(cc == .C);2243 assert(cc == .C);
2224 if (zir_args.len < fn_params_len) {2244 if (args.len < fn_params_len) {
2225 // TODO add error note: declared here2245 // TODO add error note: declared here
2226 return sema.mod.fail(2246 return sema.mod.fail(
2227 &block.base,2247 &block.base,
2228 func_src,2248 func_src,
2229 "expected at least {d} argument(s), found {d}",2249 "expected at least {d} argument(s), found {d}",
2230 .{ fn_params_len, zir_args.len },2250 .{ fn_params_len, args.len },
2231 );2251 );
2232 }2252 }
2233 } else if (fn_params_len != zir_args.len) {2253 } else if (fn_params_len != args.len) {
2234 // TODO add error note: declared here2254 // TODO add error note: declared here
2235 return sema.mod.fail(2255 return sema.mod.fail(
2236 &block.base,2256 &block.base,
2237 func_src,2257 func_src,
2238 "expected {d} argument(s), found {d}",2258 "expected {d} argument(s), found {d}",
2239 .{ fn_params_len, zir_args.len },2259 .{ fn_params_len, args.len },
2240 );2260 );
2241 }2261 }
22422262
...@@ -2256,13 +2276,6 @@ fn analyzeCall(...@@ -2256,13 +2276,6 @@ fn analyzeCall(
2256 }),2276 }),
2257 }2277 }
22582278
2259 // TODO handle function calls of generic functions
2260 const casted_args = try sema.arena.alloc(*Inst, zir_args.len);
2261 for (zir_args) |zir_arg, i| {
2262 // the args are already casted to the result of a param type instruction.
2263 casted_args[i] = try sema.resolveInst(zir_arg);
2264 }
2265
2266 const ret_type = func.ty.fnReturnType();2279 const ret_type = func.ty.fnReturnType();
22672280
2268 const is_comptime_call = block.is_comptime or modifier == .compile_time;2281 const is_comptime_call = block.is_comptime or modifier == .compile_time;
...@@ -2323,7 +2336,7 @@ fn analyzeCall(...@@ -2323,7 +2336,7 @@ fn analyzeCall(
2323 defer sema.func = parent_func;2336 defer sema.func = parent_func;
23242337
2325 const parent_param_inst_list = sema.param_inst_list;2338 const parent_param_inst_list = sema.param_inst_list;
2326 sema.param_inst_list = casted_args;2339 sema.param_inst_list = args;
2327 defer sema.param_inst_list = parent_param_inst_list;2340 defer sema.param_inst_list = parent_param_inst_list;
23282341
2329 const parent_next_arg_index = sema.next_arg_index;2342 const parent_next_arg_index = sema.next_arg_index;
...@@ -2357,7 +2370,7 @@ fn analyzeCall(...@@ -2357,7 +2370,7 @@ fn analyzeCall(
2357 break :res result;2370 break :res result;
2358 } else res: {2371 } else res: {
2359 try sema.requireRuntimeBlock(block, call_src);2372 try sema.requireRuntimeBlock(block, call_src);
2360 break :res try block.addCall(call_src, ret_type, func, casted_args);2373 break :res try block.addCall(call_src, ret_type, func, args);
2361 };2374 };
23622375
2363 if (ensure_result_used) {2376 if (ensure_result_used) {
...@@ -3081,28 +3094,31 @@ fn funcCommon(...@@ -3081,28 +3094,31 @@ fn funcCommon(
3081) InnerError!*Inst {3094) InnerError!*Inst {
3082 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3095 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3083 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3096 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
3084 const return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);3097 const bare_return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);
30853098
3086 const mod = sema.mod;3099 const mod = sema.mod;
30873100
3101 const new_func = if (body_inst == 0) undefined else try sema.gpa.create(Module.Fn);
3102 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
3103
3088 const fn_ty: Type = fn_ty: {3104 const fn_ty: Type = fn_ty: {
3089 // Hot path for some common function types.3105 // Hot path for some common function types.
3090 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and3106 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and
3091 !inferred_error_set)3107 !inferred_error_set)
3092 {3108 {
3093 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3109 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
3094 break :fn_ty Type.initTag(.fn_noreturn_no_args);3110 break :fn_ty Type.initTag(.fn_noreturn_no_args);
3095 }3111 }
30963112
3097 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {3113 if (bare_return_type.zigTypeTag() == .Void and cc == .Unspecified) {
3098 break :fn_ty Type.initTag(.fn_void_no_args);3114 break :fn_ty Type.initTag(.fn_void_no_args);
3099 }3115 }
31003116
3101 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {3117 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
3102 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);3118 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
3103 }3119 }
31043120
3105 if (return_type.zigTypeTag() == .Void and cc == .C) {3121 if (bare_return_type.zigTypeTag() == .Void and cc == .C) {
3106 break :fn_ty Type.initTag(.fn_ccc_void_no_args);3122 break :fn_ty Type.initTag(.fn_ccc_void_no_args);
3107 }3123 }
3108 }3124 }
...@@ -3120,9 +3136,13 @@ fn funcCommon(...@@ -3120,9 +3136,13 @@ fn funcCommon(
3120 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3136 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
3121 }3137 }
31223138
3123 if (inferred_error_set) {3139 const return_type = if (!inferred_error_set) bare_return_type else blk: {
3124 return mod.fail(&block.base, src, "TODO implement functions with inferred error sets", .{});3140 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, new_func);
3125 }3141 break :blk try Type.Tag.error_union.create(sema.arena, .{
3142 .error_set = error_set_ty,
3143 .payload = bare_return_type,
3144 });
3145 };
31263146
3127 break :fn_ty try Type.Tag.function.create(sema.arena, .{3147 break :fn_ty try Type.Tag.function.create(sema.arena, .{
3128 .param_types = param_types,3148 .param_types = param_types,
...@@ -3188,7 +3208,6 @@ fn funcCommon(...@@ -3188,7 +3208,6 @@ fn funcCommon(
3188 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;3208 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
31893209
3190 const fn_payload = try sema.arena.create(Value.Payload.Function);3210 const fn_payload = try sema.arena.create(Value.Payload.Function);
3191 const new_func = try sema.gpa.create(Module.Fn);
3192 new_func.* = .{3211 new_func.* = .{
3193 .state = anal_state,3212 .state = anal_state,
3194 .zir_body_inst = body_inst,3213 .zir_body_inst = body_inst,
...@@ -4542,6 +4561,12 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!...@@ -4542,6 +4561,12 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
4542 return mod.constType(sema.arena, src, file_root_decl.ty);4561 return mod.constType(sema.arena, src, file_root_decl.ty);
4543}4562}
45444563
4564fn zirRetErrValueCode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4565 _ = block;
4566 _ = inst;
4567 return sema.mod.fail(&block.base, sema.src, "TODO implement zirRetErrValueCode", .{});
4568}
4569
4545fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {4570fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
4546 const tracy = trace(@src());4571 const tracy = trace(@src());
4547 defer tracy.end();4572 defer tracy.end();
...@@ -5388,7 +5413,24 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE...@@ -5388,7 +5413,24 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
5388 }5413 }
5389}5414}
53905415
5391fn zirRetTok(5416fn zirRetErrValue(
5417 sema: *Sema,
5418 block: *Scope.Block,
5419 inst: Zir.Inst.Index,
5420) InnerError!Zir.Inst.Index {
5421 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
5422 const err_name = inst_data.get(sema.code);
5423 const src = inst_data.src();
5424
5425 // Add the error tag to the inferred error set of the in-scope function.
5426 // Return the error code from the function.
5427
5428 _ = inst_data;
5429 _ = err_name;
5430 return sema.mod.fail(&block.base, src, "TODO: Sema.zirRetErrValueCode", .{});
5431}
5432
5433fn zirRetCoerce(
5392 sema: *Sema,5434 sema: *Sema,
5393 block: *Scope.Block,5435 block: *Scope.Block,
5394 inst: Zir.Inst.Index,5436 inst: Zir.Inst.Index,
...@@ -6195,6 +6237,10 @@ fn zirFuncExtended(...@@ -6195,6 +6237,10 @@ fn zirFuncExtended(
6195 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;6237 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
6196 }6238 }
61976239
6240 const is_var_args = small.is_var_args;
6241 const is_inferred_error = small.is_inferred_error;
6242 const is_extern = small.is_extern;
6243
6198 return sema.funcCommon(6244 return sema.funcCommon(
6199 block,6245 block,
6200 extra.data.src_node,6246 extra.data.src_node,
...@@ -6203,9 +6249,9 @@ fn zirFuncExtended(...@@ -6203,9 +6249,9 @@ fn zirFuncExtended(
6203 extra.data.return_type,6249 extra.data.return_type,
6204 cc,6250 cc,
6205 align_val,6251 align_val,
6206 small.is_var_args,6252 is_var_args,
6207 small.is_inferred_error,6253 is_inferred_error,
6208 small.is_extern,6254 is_extern,
6209 src_locs,6255 src_locs,
6210 lib_name,6256 lib_name,
6211 );6257 );
...@@ -6357,15 +6403,51 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:...@@ -6357,15 +6403,51 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:
6357 try parent_block.instructions.append(sema.gpa, &block_inst.base);6403 try parent_block.instructions.append(sema.gpa, &block_inst.base);
6358}6404}
63596405
6360fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !Zir.Inst.Index {6406fn panicWithMsg(
6361 _ = sema;6407 sema: *Sema,
6362 _ = panic_id;6408 block: *Scope.Block,
6363 // TODO Once we have a panic function to call, call it here instead of breakpoint.6409 src: LazySrcLoc,
6364 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);6410 msg_inst: *ir.Inst,
6365 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);6411) !Zir.Inst.Index {
6412 const mod = sema.mod;
6413 const arena = sema.arena;
6414 const panic_fn = try sema.getBuiltin(block, src, "panic");
6415 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
6416 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
6417 const ptr_stack_trace_ty = try mod.simplePtrType(arena, stack_trace_ty, true, .One);
6418 const null_stack_trace = try mod.constInst(arena, src, .{
6419 .ty = try mod.optionalType(arena, ptr_stack_trace_ty),
6420 .val = Value.initTag(.null_value),
6421 });
6422 const args = try arena.create([2]*ir.Inst);
6423 args.* = .{ msg_inst, null_stack_trace };
6424 _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, args);
6366 return always_noreturn;6425 return always_noreturn;
6367}6426}
63686427
6428fn safetyPanic(
6429 sema: *Sema,
6430 block: *Scope.Block,
6431 src: LazySrcLoc,
6432 panic_id: PanicId,
6433) !Zir.Inst.Index {
6434 const mod = sema.mod;
6435 const arena = sema.arena;
6436 const msg = switch (panic_id) {
6437 .unreach => "reached unreachable code",
6438 .unwrap_null => "attempt to use null value",
6439 .unwrap_errunion => "unreachable error occurred",
6440 .cast_to_null => "cast causes pointer to be null",
6441 .incorrect_alignment => "incorrect alignment",
6442 .invalid_error_code => "invalid error code",
6443 };
6444 const msg_inst = try mod.constInst(arena, src, .{
6445 .ty = Type.initTag(.const_slice_u8),
6446 .val = try Value.Tag.ref_val.create(arena, try Value.Tag.bytes.create(arena, msg)),
6447 });
6448 return sema.panicWithMsg(block, src, msg_inst);
6449}
6450
6369fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {6451fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
6370 sema.branch_count += 1;6452 sema.branch_count += 1;
6371 if (sema.branch_count > sema.branch_quota) {6453 if (sema.branch_count > sema.branch_quota) {
...@@ -7377,15 +7459,13 @@ fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst)...@@ -7377,15 +7459,13 @@ fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst)
7377}7459}
73787460
7379fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {7461fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
7380 // TODO deal with inferred error sets
7381 const err_union = dest_type.castTag(.error_union).?;7462 const err_union = dest_type.castTag(.error_union).?;
7382 if (inst.value()) |val| {7463 if (inst.value()) |val| {
7383 const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {7464 if (inst.ty.zigTypeTag() != .ErrorSet) {
7384 _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);7465 _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);
7385 break :blk val;
7386 } else switch (err_union.data.error_set.tag()) {7466 } else switch (err_union.data.error_set.tag()) {
7387 .anyerror => val,7467 .anyerror => {},
7388 .error_set_single => blk: {7468 .error_set_single => {
7389 const expected_name = val.castTag(.@"error").?.data.name;7469 const expected_name = val.castTag(.@"error").?.data.name;
7390 const n = err_union.data.error_set.castTag(.error_set_single).?.data;7470 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
7391 if (!mem.eql(u8, expected_name, n)) {7471 if (!mem.eql(u8, expected_name, n)) {
...@@ -7396,9 +7476,8 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst...@@ -7396,9 +7476,8 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst
7396 .{ err_union.data.error_set, inst.ty },7476 .{ err_union.data.error_set, inst.ty },
7397 );7477 );
7398 }7478 }
7399 break :blk val;
7400 },7479 },
7401 .error_set => blk: {7480 .error_set => {
7402 const expected_name = val.castTag(.@"error").?.data.name;7481 const expected_name = val.castTag(.@"error").?.data.name;
7403 const error_set = err_union.data.error_set.castTag(.error_set).?.data;7482 const error_set = err_union.data.error_set.castTag(.error_set).?.data;
7404 const names = error_set.names_ptr[0..error_set.names_len];7483 const names = error_set.names_ptr[0..error_set.names_len];
...@@ -7415,18 +7494,14 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst...@@ -7415,18 +7494,14 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst
7415 .{ err_union.data.error_set, inst.ty },7494 .{ err_union.data.error_set, inst.ty },
7416 );7495 );
7417 }7496 }
7418 break :blk val;
7419 },7497 },
7420 else => unreachable,7498 else => unreachable,
7421 };7499 }
74227500
7423 return sema.mod.constInst(sema.arena, inst.src, .{7501 return sema.mod.constInst(sema.arena, inst.src, .{
7424 .ty = dest_type,7502 .ty = dest_type,
7425 // creating a SubValue for the error_union payload7503 // creating a SubValue for the error_union payload
7426 .val = try Value.Tag.error_union.create(7504 .val = try Value.Tag.error_union.create(sema.arena, val),
7427 sema.arena,
7428 to_wrap,
7429 ),
7430 });7505 });
7431 }7506 }
74327507
...@@ -7573,12 +7648,12 @@ fn resolveBuiltinTypeFields(...@@ -7573,12 +7648,12 @@ fn resolveBuiltinTypeFields(
7573 return sema.resolveTypeFields(block, src, resolved_ty);7648 return sema.resolveTypeFields(block, src, resolved_ty);
7574}7649}
75757650
7576fn getBuiltinType(7651fn getBuiltin(
7577 sema: *Sema,7652 sema: *Sema,
7578 block: *Scope.Block,7653 block: *Scope.Block,
7579 src: LazySrcLoc,7654 src: LazySrcLoc,
7580 name: []const u8,7655 name: []const u8,
7581) InnerError!Type {7656) InnerError!*ir.Inst {
7582 const mod = sema.mod;7657 const mod = sema.mod;
7583 const std_pkg = mod.root_pkg.table.get("std").?;7658 const std_pkg = mod.root_pkg.table.get("std").?;
7584 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;7659 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
...@@ -7596,7 +7671,16 @@ fn getBuiltinType(...@@ -7596,7 +7671,16 @@ fn getBuiltinType(
7596 builtin_ty.getNamespace().?,7671 builtin_ty.getNamespace().?,
7597 name,7672 name,
7598 );7673 );
7599 const ty_inst = try sema.analyzeLoad(block, src, opt_ty_inst.?, src);7674 return sema.analyzeLoad(block, src, opt_ty_inst.?, src);
7675}
7676
7677fn getBuiltinType(
7678 sema: *Sema,
7679 block: *Scope.Block,
7680 src: LazySrcLoc,
7681 name: []const u8,
7682) InnerError!Type {
7683 const ty_inst = try sema.getBuiltin(block, src, name);
7600 return sema.resolveAirAsType(block, src, ty_inst);7684 return sema.resolveAirAsType(block, src, ty_inst);
7601}7685}
76027686
...@@ -7662,6 +7746,7 @@ fn typeHasOnePossibleValue(...@@ -7662,6 +7746,7 @@ fn typeHasOnePossibleValue(
7662 .error_union,7746 .error_union,
7663 .error_set,7747 .error_set,
7664 .error_set_single,7748 .error_set_single,
7749 .error_set_inferred,
7665 .@"opaque",7750 .@"opaque",
7666 .var_args_param,7751 .var_args_param,
7667 .manyptr_u8,7752 .manyptr_u8,
src/Zir.zig+23-4
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these
2//! untyped IR instructions. Next, Sema.zig processes these into TZIR.2//! untyped IR instructions. Next, Sema.zig processes these into AIR.
3//! The minimum amount of information needed to represent a list of ZIR instructions.3//! The minimum amount of information needed to represent a list of ZIR instructions.
4//! Once this structure is completed, it can be used to generate TZIR, followed by4//! Once this structure is completed, it can be used to generate AIR, followed by
5//! machine code, without any memory access into the AST tree token list, node list,5//! machine code, without any memory access into the AST tree token list, node list,
6//! or source bytes. Exceptions include:6//! or source bytes. Exceptions include:
7//! * Compile errors, which may need to reach into these data structures to7//! * Compile errors, which may need to reach into these data structures to
...@@ -416,8 +416,8 @@ pub const Inst = struct {...@@ -416,8 +416,8 @@ pub const Inst = struct {
416 /// A labeled block of code that loops forever. At the end of the body will have either416 /// A labeled block of code that loops forever. At the end of the body will have either
417 /// a `repeat` instruction or a `repeat_inline` instruction.417 /// a `repeat` instruction or a `repeat_inline` instruction.
418 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.418 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
419 /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema419 /// This ZIR instruction is needed because AIR does not (yet?) match ZIR, and Sema
420 /// needs to emit more than 1 TZIR block for this instruction.420 /// needs to emit more than 1 AIR block for this instruction.
421 /// The payload is `Block`.421 /// The payload is `Block`.
422 loop,422 loop,
423 /// Sends runtime control flow back to the beginning of the current block.423 /// Sends runtime control flow back to the beginning of the current block.
...@@ -466,6 +466,19 @@ pub const Inst = struct {...@@ -466,6 +466,19 @@ pub const Inst = struct {
466 /// Uses the `un_tok` union field.466 /// Uses the `un_tok` union field.
467 /// The operand needs to get coerced to the function's return type.467 /// The operand needs to get coerced to the function's return type.
468 ret_coerce,468 ret_coerce,
469 /// Sends control flow back to the function's callee.
470 /// The return operand is `error.foo` where `foo` is given by the string.
471 /// If the current function has an inferred error set, the error given by the
472 /// name is added to it.
473 /// Uses the `str_tok` union field.
474 ret_err_value,
475 /// A string name is provided which is an anonymous error set value.
476 /// If the current function has an inferred error set, the error given by the
477 /// name is added to it.
478 /// Results in the error code. Note that control flow is not diverted with
479 /// this instruction; a following 'ret' instruction will do the diversion.
480 /// Uses the `str_tok` union field.
481 ret_err_value_code,
469 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.482 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
470 /// Uses the `ptr_type_simple` union field.483 /// Uses the `ptr_type_simple` union field.
471 ptr_type_simple,484 ptr_type_simple,
...@@ -1193,6 +1206,7 @@ pub const Inst = struct {...@@ -1193,6 +1206,7 @@ pub const Inst = struct {
1193 .@"resume",1206 .@"resume",
1194 .@"await",1207 .@"await",
1195 .await_nosuspend,1208 .await_nosuspend,
1209 .ret_err_value_code,
1196 .extended,1210 .extended,
1197 => false,1211 => false,
11981212
...@@ -1203,6 +1217,7 @@ pub const Inst = struct {...@@ -1203,6 +1217,7 @@ pub const Inst = struct {
1203 .compile_error,1217 .compile_error,
1204 .ret_node,1218 .ret_node,
1205 .ret_coerce,1219 .ret_coerce,
1220 .ret_err_value,
1206 .@"unreachable",1221 .@"unreachable",
1207 .repeat,1222 .repeat,
1208 .repeat_inline,1223 .repeat_inline,
...@@ -1307,6 +1322,8 @@ pub const Inst = struct {...@@ -1307,6 +1322,8 @@ pub const Inst = struct {
1307 .ref = .un_tok,1322 .ref = .un_tok,
1308 .ret_node = .un_node,1323 .ret_node = .un_node,
1309 .ret_coerce = .un_tok,1324 .ret_coerce = .un_tok,
1325 .ret_err_value = .str_tok,
1326 .ret_err_value_code = .str_tok,
1310 .ptr_type_simple = .ptr_type_simple,1327 .ptr_type_simple = .ptr_type_simple,
1311 .ptr_type = .ptr_type,1328 .ptr_type = .ptr_type,
1312 .slice_start = .pl_node,1329 .slice_start = .pl_node,
...@@ -3077,6 +3094,8 @@ const Writer = struct {...@@ -3077,6 +3094,8 @@ const Writer = struct {
3077 .decl_val,3094 .decl_val,
3078 .import,3095 .import,
3079 .arg,3096 .arg,
3097 .ret_err_value,
3098 .ret_err_value_code,
3080 => try self.writeStrTok(stream, inst),3099 => try self.writeStrTok(stream, inst),
30813100
3082 .func => try self.writeFunc(stream, inst, false),3101 .func => try self.writeFunc(stream, inst, false),
src/air.zig+11-11
...@@ -672,15 +672,15 @@ pub const Body = struct {...@@ -672,15 +672,15 @@ pub const Body = struct {
672/// For debugging purposes, prints a function representation to stderr.672/// For debugging purposes, prints a function representation to stderr.
673pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {673pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
674 const allocator = old_module.gpa;674 const allocator = old_module.gpa;
675 var ctx: DumpTzir = .{675 var ctx: DumpAir = .{
676 .allocator = allocator,676 .allocator = allocator,
677 .arena = std.heap.ArenaAllocator.init(allocator),677 .arena = std.heap.ArenaAllocator.init(allocator),
678 .old_module = &old_module,678 .old_module = &old_module,
679 .module_fn = module_fn,679 .module_fn = module_fn,
680 .indent = 2,680 .indent = 2,
681 .inst_table = DumpTzir.InstTable.init(allocator),681 .inst_table = DumpAir.InstTable.init(allocator),
682 .partial_inst_table = DumpTzir.InstTable.init(allocator),682 .partial_inst_table = DumpAir.InstTable.init(allocator),
683 .const_table = DumpTzir.InstTable.init(allocator),683 .const_table = DumpAir.InstTable.init(allocator),
684 };684 };
685 defer ctx.inst_table.deinit();685 defer ctx.inst_table.deinit();
686 defer ctx.partial_inst_table.deinit();686 defer ctx.partial_inst_table.deinit();
...@@ -695,12 +695,12 @@ pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {...@@ -695,12 +695,12 @@ pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
695 .dependency_failure => std.debug.print("(dependency_failure)", .{}),695 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
696 .success => {696 .success => {
697 const writer = std.io.getStdErr().writer();697 const writer = std.io.getStdErr().writer();
698 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");698 ctx.dump(module_fn.body, writer) catch @panic("failed to dump AIR");
699 },699 },
700 }700 }
701}701}
702702
703const DumpTzir = struct {703const DumpAir = struct {
704 allocator: *std.mem.Allocator,704 allocator: *std.mem.Allocator,
705 arena: std.heap.ArenaAllocator,705 arena: std.heap.ArenaAllocator,
706 old_module: *const Module,706 old_module: *const Module,
...@@ -718,7 +718,7 @@ const DumpTzir = struct {...@@ -718,7 +718,7 @@ const DumpTzir = struct {
718 /// TODO: Improve this code to include a stack of Body and store the instructions718 /// TODO: Improve this code to include a stack of Body and store the instructions
719 /// in there. Now we are putting all the instructions in a function local table,719 /// in there. Now we are putting all the instructions in a function local table,
720 /// however instructions that are in a Body can be thown away when the Body ends.720 /// however instructions that are in a Body can be thown away when the Body ends.
721 fn dump(dtz: *DumpTzir, body: Body, writer: std.fs.File.Writer) !void {721 fn dump(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) !void {
722 // First pass to pre-populate the table so that we can show even invalid references.722 // First pass to pre-populate the table so that we can show even invalid references.
723 // Must iterate the same order we iterate the second time.723 // Must iterate the same order we iterate the second time.
724 // We also look for constants and put them in the const_table.724 // We also look for constants and put them in the const_table.
...@@ -737,7 +737,7 @@ const DumpTzir = struct {...@@ -737,7 +737,7 @@ const DumpTzir = struct {
737 return dtz.dumpBody(body, writer);737 return dtz.dumpBody(body, writer);
738 }738 }
739739
740 fn fetchInstsAndResolveConsts(dtz: *DumpTzir, body: Body) error{OutOfMemory}!void {740 fn fetchInstsAndResolveConsts(dtz: *DumpAir, body: Body) error{OutOfMemory}!void {
741 for (body.instructions) |inst| {741 for (body.instructions) |inst| {
742 try dtz.inst_table.put(inst, dtz.next_index);742 try dtz.inst_table.put(inst, dtz.next_index);
743 dtz.next_index += 1;743 dtz.next_index += 1;
...@@ -865,7 +865,7 @@ const DumpTzir = struct {...@@ -865,7 +865,7 @@ const DumpTzir = struct {
865 }865 }
866 }866 }
867867
868 fn dumpBody(dtz: *DumpTzir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {868 fn dumpBody(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {
869 for (body.instructions) |inst| {869 for (body.instructions) |inst| {
870 const my_index = dtz.next_partial_index;870 const my_index = dtz.next_partial_index;
871 try dtz.partial_inst_table.put(inst, my_index);871 try dtz.partial_inst_table.put(inst, my_index);
...@@ -1150,7 +1150,7 @@ const DumpTzir = struct {...@@ -1150,7 +1150,7 @@ const DumpTzir = struct {
1150 }1150 }
1151 }1151 }
11521152
1153 fn writeInst(dtz: *DumpTzir, writer: std.fs.File.Writer, inst: *Inst) !?usize {1153 fn writeInst(dtz: *DumpAir, writer: std.fs.File.Writer, inst: *Inst) !?usize {
1154 if (dtz.partial_inst_table.get(inst)) |operand_index| {1154 if (dtz.partial_inst_table.get(inst)) |operand_index| {
1155 try writer.print("%{d}", .{operand_index});1155 try writer.print("%{d}", .{operand_index});
1156 return null;1156 return null;
...@@ -1166,7 +1166,7 @@ const DumpTzir = struct {...@@ -1166,7 +1166,7 @@ const DumpTzir = struct {
1166 }1166 }
1167 }1167 }
11681168
1169 fn findConst(dtz: *DumpTzir, operand: *Inst) !void {1169 fn findConst(dtz: *DumpAir, operand: *Inst) !void {
1170 if (operand.tag == .constant) {1170 if (operand.tag == .constant) {
1171 try dtz.const_table.put(operand, dtz.next_const_index);1171 try dtz.const_table.put(operand, dtz.next_const_index);
1172 dtz.next_const_index += 1;1172 dtz.next_const_index += 1;
src/codegen/c.zig+229-60
...@@ -39,7 +39,12 @@ const BlockData = struct {...@@ -39,7 +39,12 @@ const BlockData = struct {
39};39};
4040
41pub const CValueMap = std.AutoHashMap(*Inst, CValue);41pub const CValueMap = std.AutoHashMap(*Inst, CValue);
42pub const TypedefMap = std.HashMap(Type, struct { name: []const u8, rendered: []u8 }, Type.HashContext, std.hash_map.default_max_load_percentage);42pub const TypedefMap = std.HashMap(
43 Type,
44 struct { name: []const u8, rendered: []u8 },
45 Type.HashContext,
46 std.hash_map.default_max_load_percentage,
47);
4348
44fn formatTypeAsCIdentifier(49fn formatTypeAsCIdentifier(
45 data: Type,50 data: Type,
...@@ -151,14 +156,49 @@ pub const Object = struct {...@@ -151,14 +156,49 @@ pub const Object = struct {
151 render_ty = render_ty.elemType();156 render_ty = render_ty.elemType();
152 }157 }
153158
154 try o.dg.renderType(w, render_ty);159 if (render_ty.zigTypeTag() == .Fn) {
155160 const ret_ty = render_ty.fnReturnType();
156 const const_prefix = switch (mutability) {161 if (ret_ty.zigTypeTag() == .NoReturn) {
157 .Const => "const ",162 // noreturn attribute is not allowed here.
158 .Mut => "",163 try w.writeAll("void");
159 };164 } else {
160 try w.print(" {s}", .{const_prefix});165 try o.dg.renderType(w, ret_ty);
161 try o.writeCValue(w, name);166 }
167 try w.writeAll(" (*");
168 switch (mutability) {
169 .Const => try w.writeAll("const "),
170 .Mut => {},
171 }
172 try o.writeCValue(w, name);
173 try w.writeAll(")(");
174 const param_len = render_ty.fnParamLen();
175 const is_var_args = render_ty.fnIsVarArgs();
176 if (param_len == 0 and !is_var_args)
177 try w.writeAll("void")
178 else {
179 var index: usize = 0;
180 while (index < param_len) : (index += 1) {
181 if (index > 0) {
182 try w.writeAll(", ");
183 }
184 try o.dg.renderType(w, render_ty.fnParamType(index));
185 }
186 }
187 if (is_var_args) {
188 if (param_len != 0) try w.writeAll(", ");
189 try w.writeAll("...");
190 }
191 try w.writeByte(')');
192 } else {
193 try o.dg.renderType(w, render_ty);
194
195 const const_prefix = switch (mutability) {
196 .Const => "const ",
197 .Mut => "",
198 };
199 try w.print(" {s}", .{const_prefix});
200 try o.writeCValue(w, name);
201 }
162 try w.writeAll(suffix.items);202 try w.writeAll(suffix.items);
163 }203 }
164};204};
...@@ -196,35 +236,72 @@ pub const DeclGen = struct {...@@ -196,35 +236,72 @@ pub const DeclGen = struct {
196 return writer.print("{d}", .{val.toSignedInt()});236 return writer.print("{d}", .{val.toSignedInt()});
197 return writer.print("{d}", .{val.toUnsignedInt()});237 return writer.print("{d}", .{val.toUnsignedInt()});
198 },238 },
199 .Pointer => switch (val.tag()) {239 .Pointer => switch (t.ptrSize()) {
200 .null_value, .zero => try writer.writeAll("NULL"),240 .Slice => {
201 .one => try writer.writeAll("1"),241 try writer.writeByte('(');
202 .decl_ref => {242 try dg.renderType(writer, t);
203 const decl = val.castTag(.decl_ref).?.data;243 try writer.writeAll("){");
204244 var buf: Type.Payload.ElemType = undefined;
205 // Determine if we must pointer cast.245 try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
206 assert(decl.has_tv);246 try writer.writeAll(", ");
207 if (t.eql(decl.ty)) {247 try writer.print("{d}", .{val.sliceLen()});
208 try writer.print("&{s}", .{decl.name});248 try writer.writeAll("}");
209 } else {
210 try writer.writeAll("(");
211 try dg.renderType(writer, t);
212 try writer.print(")&{s}", .{decl.name});
213 }
214 },
215 .function => {
216 const func = val.castTag(.function).?.data;
217 try writer.print("{s}", .{func.owner_decl.name});
218 },249 },
219 .extern_fn => {250 else => switch (val.tag()) {
220 const decl = val.castTag(.extern_fn).?.data;251 .null_value, .zero => try writer.writeAll("NULL"),
221 try writer.print("{s}", .{decl.name});252 .one => try writer.writeAll("1"),
253 .decl_ref => {
254 const decl = val.castTag(.decl_ref).?.data;
255
256 // Determine if we must pointer cast.
257 assert(decl.has_tv);
258 if (t.eql(decl.ty)) {
259 try writer.print("&{s}", .{decl.name});
260 } else {
261 try writer.writeAll("(");
262 try dg.renderType(writer, t);
263 try writer.print(")&{s}", .{decl.name});
264 }
265 },
266 .function => {
267 const func = val.castTag(.function).?.data;
268 try writer.print("{s}", .{func.owner_decl.name});
269 },
270 .extern_fn => {
271 const decl = val.castTag(.extern_fn).?.data;
272 try writer.print("{s}", .{decl.name});
273 },
274 else => switch (t.ptrSize()) {
275 .Slice => unreachable,
276 .Many => {
277 if (val.castTag(.ref_val)) |ref_val_payload| {
278 const sub_val = ref_val_payload.data;
279 if (sub_val.castTag(.bytes)) |bytes_payload| {
280 const bytes = bytes_payload.data;
281 try writer.writeByte('(');
282 try dg.renderType(writer, t);
283 // TODO: make our own C string escape instead of using std.zig.fmtEscapes
284 try writer.print(")\"{}\"", .{std.zig.fmtEscapes(bytes)});
285 } else {
286 unreachable;
287 }
288 } else {
289 unreachable;
290 }
291 },
292 .One => {
293 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
294 defer arena.deinit();
295
296 const elem_ty = t.elemType();
297 const elem_val = try val.pointerDeref(&arena.allocator);
298
299 try writer.writeAll("&");
300 try dg.renderValue(writer, elem_ty, elem_val);
301 },
302 .C => unreachable,
303 },
222 },304 },
223 else => |e| return dg.fail(
224 .{ .node_offset = 0 },
225 "TODO: C backend: implement Pointer value {s}",
226 .{@tagName(e)},
227 ),
228 },305 },
229 .Array => {306 .Array => {
230 // First try specific tag representations for more efficiency.307 // First try specific tag representations for more efficiency.
...@@ -329,6 +406,32 @@ pub const DeclGen = struct {...@@ -329,6 +406,32 @@ pub const DeclGen = struct {
329 },406 },
330 }407 }
331 },408 },
409 .Fn => switch (val.tag()) {
410 .null_value, .zero => try writer.writeAll("NULL"),
411 .one => try writer.writeAll("1"),
412 .decl_ref => {
413 const decl = val.castTag(.decl_ref).?.data;
414
415 // Determine if we must pointer cast.
416 assert(decl.has_tv);
417 if (t.eql(decl.ty)) {
418 try writer.print("&{s}", .{decl.name});
419 } else {
420 try writer.writeAll("(");
421 try dg.renderType(writer, t);
422 try writer.print(")&{s}", .{decl.name});
423 }
424 },
425 .function => {
426 const func = val.castTag(.function).?.data;
427 try writer.print("{s}", .{func.owner_decl.name});
428 },
429 .extern_fn => {
430 const decl = val.castTag(.extern_fn).?.data;
431 try writer.print("{s}", .{decl.name});
432 },
433 else => unreachable,
434 },
332 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{435 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
333 @tagName(e),436 @tagName(e),
334 }),437 }),
...@@ -339,6 +442,12 @@ pub const DeclGen = struct {...@@ -339,6 +442,12 @@ pub const DeclGen = struct {
339 if (!is_global) {442 if (!is_global) {
340 try w.writeAll("static ");443 try w.writeAll("static ");
341 }444 }
445 if (dg.decl.val.castTag(.function)) |func_payload| {
446 const func: *Module.Fn = func_payload.data;
447 if (func.is_cold) {
448 try w.writeAll("ZIG_COLD ");
449 }
450 }
342 try dg.renderType(w, dg.decl.ty.fnReturnType());451 try dg.renderType(w, dg.decl.ty.fnReturnType());
343 const decl_name = mem.span(dg.decl.name);452 const decl_name = mem.span(dg.decl.name);
344 try w.print(" {s}(", .{decl_name});453 try w.print(" {s}(", .{decl_name});
...@@ -413,7 +522,35 @@ pub const DeclGen = struct {...@@ -413,7 +522,35 @@ pub const DeclGen = struct {
413522
414 .Pointer => {523 .Pointer => {
415 if (t.isSlice()) {524 if (t.isSlice()) {
416 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});525 if (dg.typedefs.get(t)) |some| {
526 return w.writeAll(some.name);
527 }
528
529 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
530 defer buffer.deinit();
531 const bw = buffer.writer();
532
533 try bw.writeAll("typedef struct { ");
534 const elem_type = t.elemType();
535 try dg.renderType(bw, elem_type);
536 try bw.writeAll(" *");
537 if (t.isConstPtr()) {
538 try bw.writeAll("const ");
539 }
540 if (t.isVolatilePtr()) {
541 try bw.writeAll("volatile ");
542 }
543 try bw.writeAll("ptr; size_t len; } ");
544 const name_index = buffer.items.len;
545 try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)});
546
547 const rendered = buffer.toOwnedSlice();
548 errdefer dg.typedefs.allocator.free(rendered);
549 const name = rendered[name_index .. rendered.len - 2];
550
551 try dg.typedefs.ensureUnusedCapacity(1);
552 try w.writeAll(name);
553 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
417 } else {554 } else {
418 try dg.renderType(w, t.elemType());555 try dg.renderType(w, t.elemType());
419 try w.writeAll(" *");556 try w.writeAll(" *");
...@@ -446,13 +583,13 @@ pub const DeclGen = struct {...@@ -446,13 +583,13 @@ pub const DeclGen = struct {
446 try dg.renderType(bw, child_type);583 try dg.renderType(bw, child_type);
447 try bw.writeAll(" payload; bool is_null; } ");584 try bw.writeAll(" payload; bool is_null; } ");
448 const name_index = buffer.items.len;585 const name_index = buffer.items.len;
449 try bw.print("zig_opt_{s}_t;\n", .{typeToCIdentifier(child_type)});586 try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type)});
450587
451 const rendered = buffer.toOwnedSlice();588 const rendered = buffer.toOwnedSlice();
452 errdefer dg.typedefs.allocator.free(rendered);589 errdefer dg.typedefs.allocator.free(rendered);
453 const name = rendered[name_index .. rendered.len - 2];590 const name = rendered[name_index .. rendered.len - 2];
454591
455 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);592 try dg.typedefs.ensureUnusedCapacity(1);
456 try w.writeAll(name);593 try w.writeAll(name);
457 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });594 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
458 },595 },
...@@ -465,7 +602,7 @@ pub const DeclGen = struct {...@@ -465,7 +602,7 @@ pub const DeclGen = struct {
465 return w.writeAll(some.name);602 return w.writeAll(some.name);
466 }603 }
467 const child_type = t.errorUnionChild();604 const child_type = t.errorUnionChild();
468 const set_type = t.errorUnionSet();605 const err_set_type = t.errorUnionSet();
469606
470 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);607 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
471 defer buffer.deinit();608 defer buffer.deinit();
...@@ -475,13 +612,20 @@ pub const DeclGen = struct {...@@ -475,13 +612,20 @@ pub const DeclGen = struct {
475 try dg.renderType(bw, child_type);612 try dg.renderType(bw, child_type);
476 try bw.writeAll(" payload; uint16_t error; } ");613 try bw.writeAll(" payload; uint16_t error; } ");
477 const name_index = buffer.items.len;614 const name_index = buffer.items.len;
478 try bw.print("zig_err_union_{s}_{s}_t;\n", .{ typeToCIdentifier(set_type), typeToCIdentifier(child_type) });615 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
616 const func = inf_err_set_payload.data;
617 try bw.print("zig_E_{s};\n", .{func.owner_decl.name});
618 } else {
619 try bw.print("zig_E_{s}_{s};\n", .{
620 typeToCIdentifier(err_set_type), typeToCIdentifier(child_type),
621 });
622 }
479623
480 const rendered = buffer.toOwnedSlice();624 const rendered = buffer.toOwnedSlice();
481 errdefer dg.typedefs.allocator.free(rendered);625 errdefer dg.typedefs.allocator.free(rendered);
482 const name = rendered[name_index .. rendered.len - 2];626 const name = rendered[name_index .. rendered.len - 2];
483627
484 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);628 try dg.typedefs.ensureUnusedCapacity(1);
485 try w.writeAll(name);629 try w.writeAll(name);
486 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });630 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
487 },631 },
...@@ -514,7 +658,7 @@ pub const DeclGen = struct {...@@ -514,7 +658,7 @@ pub const DeclGen = struct {
514 errdefer dg.typedefs.allocator.free(rendered);658 errdefer dg.typedefs.allocator.free(rendered);
515 const name = rendered[name_start .. rendered.len - 2];659 const name = rendered[name_start .. rendered.len - 2];
516660
517 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);661 try dg.typedefs.ensureUnusedCapacity(1);
518 try w.writeAll(name);662 try w.writeAll(name);
519 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });663 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
520 },664 },
...@@ -526,7 +670,28 @@ pub const DeclGen = struct {...@@ -526,7 +670,28 @@ pub const DeclGen = struct {
526 try dg.renderType(w, int_tag_ty);670 try dg.renderType(w, int_tag_ty);
527 },671 },
528 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),672 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),
529 .Fn => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Fn", .{}),673 .Fn => {
674 try dg.renderType(w, t.fnReturnType());
675 try w.writeAll(" (*)(");
676 const param_len = t.fnParamLen();
677 const is_var_args = t.fnIsVarArgs();
678 if (param_len == 0 and !is_var_args)
679 try w.writeAll("void")
680 else {
681 var index: usize = 0;
682 while (index < param_len) : (index += 1) {
683 if (index > 0) {
684 try w.writeAll(", ");
685 }
686 try dg.renderType(w, t.fnParamType(index));
687 }
688 }
689 if (is_var_args) {
690 if (param_len != 0) try w.writeAll(", ");
691 try w.writeAll("...");
692 }
693 try w.writeByte(')');
694 },
530 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),695 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),
531 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),696 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),
532 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),697 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),
...@@ -569,23 +734,27 @@ pub fn genDecl(o: *Object) !void {...@@ -569,23 +734,27 @@ pub fn genDecl(o: *Object) !void {
569 .val = o.dg.decl.val,734 .val = o.dg.decl.val,
570 };735 };
571 if (tv.val.castTag(.function)) |func_payload| {736 if (tv.val.castTag(.function)) |func_payload| {
572 const is_global = o.dg.declIsGlobal(tv);
573 const fwd_decl_writer = o.dg.fwd_decl.writer();
574 if (is_global) {
575 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
576 }
577 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
578 try fwd_decl_writer.writeAll(";\n");
579
580 const func: *Module.Fn = func_payload.data;737 const func: *Module.Fn = func_payload.data;
581 try o.indent_writer.insertNewline();738 if (func.owner_decl == o.dg.decl) {
582 try o.dg.renderFunctionSignature(o.writer(), is_global);739 const is_global = o.dg.declIsGlobal(tv);
740 const fwd_decl_writer = o.dg.fwd_decl.writer();
741 if (is_global) {
742 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
743 }
744 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
745 try fwd_decl_writer.writeAll(";\n");
583746
584 try o.writer().writeByte(' ');747 try o.indent_writer.insertNewline();
585 try genBody(o, func.body);748 try o.dg.renderFunctionSignature(o.writer(), is_global);
586749
587 try o.indent_writer.insertNewline();750 try o.writer().writeByte(' ');
588 } else if (tv.val.tag() == .extern_fn) {751 try genBody(o, func.body);
752
753 try o.indent_writer.insertNewline();
754 return;
755 }
756 }
757 if (tv.val.tag() == .extern_fn) {
589 const writer = o.writer();758 const writer = o.writer();
590 try writer.writeAll("ZIG_EXTERN_C ");759 try writer.writeAll("ZIG_EXTERN_C ");
591 try o.dg.renderFunctionSignature(writer, true);760 try o.dg.renderFunctionSignature(writer, true);
...@@ -644,9 +813,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -644,9 +813,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
644 const is_global = dg.declIsGlobal(tv);813 const is_global = dg.declIsGlobal(tv);
645 if (is_global) {814 if (is_global) {
646 try writer.writeAll("ZIG_EXTERN_C ");815 try writer.writeAll("ZIG_EXTERN_C ");
816 try dg.renderFunctionSignature(writer, is_global);
817 try dg.fwd_decl.appendSlice(";\n");
647 }818 }
648 try dg.renderFunctionSignature(writer, is_global);
649 try dg.fwd_decl.appendSlice(";\n");
650 },819 },
651 else => {},820 else => {},
652 }821 }
src/link/C.zig+4-6
...@@ -207,7 +207,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -207,7 +207,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
207 }207 }
208208
209 var fn_count: usize = 0;209 var fn_count: usize = 0;
210 var typedefs = std.HashMap(Type, []const u8, Type.HashContext, std.hash_map.default_max_load_percentage).init(comp.gpa);210 var typedefs = std.HashMap(Type, void, Type.HashContext, std.hash_map.default_max_load_percentage).init(comp.gpa);
211 defer typedefs.deinit();211 defer typedefs.deinit();
212212
213 // Typedefs, forward decls and non-functions first.213 // Typedefs, forward decls and non-functions first.
...@@ -217,14 +217,12 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -217,14 +217,12 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
217 if (!decl.has_tv) continue;217 if (!decl.has_tv) continue;
218 const buf = buf: {218 const buf = buf: {
219 if (decl.val.castTag(.function)) |_| {219 if (decl.val.castTag(.function)) |_| {
220 try typedefs.ensureUnusedCapacity(decl.fn_link.c.typedefs.count());
220 var it = decl.fn_link.c.typedefs.iterator();221 var it = decl.fn_link.c.typedefs.iterator();
221 while (it.next()) |new| {222 while (it.next()) |new| {
222 if (typedefs.get(new.key_ptr.*)) |previous| {223 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
223 try err_typedef_writer.print("typedef {s} {s};\n", .{ previous, new.value_ptr.name });224 if (!gop.found_existing) {
224 } else {
225 try typedefs.ensureCapacity(typedefs.capacity() + 1);
226 try err_typedef_writer.writeAll(new.value_ptr.rendered);225 try err_typedef_writer.writeAll(new.value_ptr.rendered);
227 typedefs.putAssumeCapacityNoClobber(new.key_ptr.*, new.value_ptr.name);
228 }226 }
229 }227 }
230 fn_count += 1;228 fn_count += 1;
src/link/C/zig.h+6
...@@ -12,6 +12,12 @@...@@ -12,6 +12,12 @@
12#define zig_threadlocal zig_threadlocal_unavailable12#define zig_threadlocal zig_threadlocal_unavailable
13#endif13#endif
1414
15#if __GNUC__
16#define ZIG_COLD __attribute__ ((cold))
17#else
18#define ZIG_COLD
19#endif
20
15#if __STDC_VERSION__ >= 199901L21#if __STDC_VERSION__ >= 199901L
16#define ZIG_RESTRICT restrict22#define ZIG_RESTRICT restrict
17#elif defined(__GNUC__)23#elif defined(__GNUC__)
src/type.zig+79-3
...@@ -58,7 +58,7 @@ pub const Type = extern union {...@@ -58,7 +58,7 @@ pub const Type = extern union {
58 .bool => return .Bool,58 .bool => return .Bool,
59 .void => return .Void,59 .void => return .Void,
60 .type => return .Type,60 .type => return .Type,
61 .error_set, .error_set_single, .anyerror => return .ErrorSet,61 .error_set, .error_set_single, .anyerror, .error_set_inferred => return .ErrorSet,
62 .comptime_int => return .ComptimeInt,62 .comptime_int => return .ComptimeInt,
63 .comptime_float => return .ComptimeFloat,63 .comptime_float => return .ComptimeFloat,
64 .noreturn => return .NoReturn,64 .noreturn => return .NoReturn,
...@@ -689,7 +689,15 @@ pub const Type = extern union {...@@ -689,7 +689,15 @@ pub const Type = extern union {
689 .optional_single_mut_pointer,689 .optional_single_mut_pointer,
690 .optional_single_const_pointer,690 .optional_single_const_pointer,
691 .anyframe_T,691 .anyframe_T,
692 => return self.copyPayloadShallow(allocator, Payload.ElemType),692 => {
693 const payload = self.cast(Payload.ElemType).?;
694 const new_payload = try allocator.create(Payload.ElemType);
695 new_payload.* = .{
696 .base = .{ .tag = payload.base.tag },
697 .data = try payload.data.copy(allocator),
698 };
699 return Type{ .ptr_otherwise = &new_payload.base };
700 },
693701
694 .int_signed,702 .int_signed,
695 .int_unsigned,703 .int_unsigned,
...@@ -756,6 +764,7 @@ pub const Type = extern union {...@@ -756,6 +764,7 @@ pub const Type = extern union {
756 });764 });
757 },765 },
758 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),766 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
767 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
759 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),768 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
760 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),769 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
761 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),770 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
...@@ -1031,6 +1040,10 @@ pub const Type = extern union {...@@ -1031,6 +1040,10 @@ pub const Type = extern union {
1031 const error_set = ty.castTag(.error_set).?.data;1040 const error_set = ty.castTag(.error_set).?.data;
1032 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));1041 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
1033 },1042 },
1043 .error_set_inferred => {
1044 const func = ty.castTag(.error_set_inferred).?.data;
1045 return writer.print("(inferred error set of {s})", .{func.owner_decl.name});
1046 },
1034 .error_set_single => {1047 .error_set_single => {
1035 const name = ty.castTag(.error_set_single).?.data;1048 const name = ty.castTag(.error_set_single).?.data;
1036 return writer.print("error{{{s}}}", .{name});1049 return writer.print("error{{{s}}}", .{name});
...@@ -1144,6 +1157,7 @@ pub const Type = extern union {...@@ -1144,6 +1157,7 @@ pub const Type = extern union {
1144 .anyerror_void_error_union,1157 .anyerror_void_error_union,
1145 .error_set,1158 .error_set,
1146 .error_set_single,1159 .error_set_single,
1160 .error_set_inferred,
1147 .manyptr_u8,1161 .manyptr_u8,
1148 .manyptr_const_u8,1162 .manyptr_const_u8,
1149 .atomic_ordering,1163 .atomic_ordering,
...@@ -1161,6 +1175,9 @@ pub const Type = extern union {...@@ -1161,6 +1175,9 @@ pub const Type = extern union {
1161 .@"struct" => {1175 .@"struct" => {
1162 // TODO introduce lazy value mechanism1176 // TODO introduce lazy value mechanism
1163 const struct_obj = self.castTag(.@"struct").?.data;1177 const struct_obj = self.castTag(.@"struct").?.data;
1178 assert(struct_obj.status == .have_field_types or
1179 struct_obj.status == .layout_wip or
1180 struct_obj.status == .have_layout);
1164 for (struct_obj.fields.values()) |value| {1181 for (struct_obj.fields.values()) |value| {
1165 if (value.ty.hasCodeGenBits())1182 if (value.ty.hasCodeGenBits())
1166 return true;1183 return true;
...@@ -1348,6 +1365,7 @@ pub const Type = extern union {...@@ -1348,6 +1365,7 @@ pub const Type = extern union {
1348 .error_set_single,1365 .error_set_single,
1349 .anyerror_void_error_union,1366 .anyerror_void_error_union,
1350 .anyerror,1367 .anyerror,
1368 .error_set_inferred,
1351 => return 2, // TODO revisit this when we have the concept of the error tag type1369 => return 2, // TODO revisit this when we have the concept of the error tag type
13521370
1353 .array, .array_sentinel => return self.elemType().abiAlignment(target),1371 .array, .array_sentinel => return self.elemType().abiAlignment(target),
...@@ -1580,6 +1598,7 @@ pub const Type = extern union {...@@ -1580,6 +1598,7 @@ pub const Type = extern union {
1580 .error_set_single,1598 .error_set_single,
1581 .anyerror_void_error_union,1599 .anyerror_void_error_union,
1582 .anyerror,1600 .anyerror,
1601 .error_set_inferred,
1583 => return 2, // TODO revisit this when we have the concept of the error tag type1602 => return 2, // TODO revisit this when we have the concept of the error tag type
15841603
1585 .int_signed, .int_unsigned => {1604 .int_signed, .int_unsigned => {
...@@ -1744,6 +1763,7 @@ pub const Type = extern union {...@@ -1744,6 +1763,7 @@ pub const Type = extern union {
1744 .error_set_single,1763 .error_set_single,
1745 .anyerror_void_error_union,1764 .anyerror_void_error_union,
1746 .anyerror,1765 .anyerror,
1766 .error_set_inferred,
1747 => return 16, // TODO revisit this when we have the concept of the error tag type1767 => return 16, // TODO revisit this when we have the concept of the error tag type
17481768
1749 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,1769 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
...@@ -1863,6 +1883,48 @@ pub const Type = extern union {...@@ -1863,6 +1883,48 @@ pub const Type = extern union {
1863 };1883 };
1864 }1884 }
18651885
1886 pub fn slicePtrFieldType(self: Type, buffer: *Payload.ElemType) Type {
1887 switch (self.tag()) {
1888 .const_slice_u8 => return Type.initTag(.manyptr_const_u8),
1889
1890 .const_slice => {
1891 const elem_type = self.castTag(.const_slice).?.data;
1892 buffer.* = .{
1893 .base = .{ .tag = .many_const_pointer },
1894 .data = elem_type,
1895 };
1896 return Type.initPayload(&buffer.base);
1897 },
1898 .mut_slice => {
1899 const elem_type = self.castTag(.mut_slice).?.data;
1900 buffer.* = .{
1901 .base = .{ .tag = .many_mut_pointer },
1902 .data = elem_type,
1903 };
1904 return Type.initPayload(&buffer.base);
1905 },
1906
1907 .pointer => {
1908 const payload = self.castTag(.pointer).?.data;
1909 assert(payload.size == .Slice);
1910 if (payload.mutable) {
1911 buffer.* = .{
1912 .base = .{ .tag = .many_mut_pointer },
1913 .data = payload.pointee_type,
1914 };
1915 } else {
1916 buffer.* = .{
1917 .base = .{ .tag = .many_const_pointer },
1918 .data = payload.pointee_type,
1919 };
1920 }
1921 return Type.initPayload(&buffer.base);
1922 },
1923
1924 else => unreachable,
1925 }
1926 }
1927
1866 pub fn isConstPtr(self: Type) bool {1928 pub fn isConstPtr(self: Type) bool {
1867 return switch (self.tag()) {1929 return switch (self.tag()) {
1868 .single_const_pointer,1930 .single_const_pointer,
...@@ -1915,7 +1977,10 @@ pub const Type = extern union {...@@ -1915,7 +1977,10 @@ pub const Type = extern union {
1915 /// Asserts that the type is an optional1977 /// Asserts that the type is an optional
1916 pub fn isPtrLikeOptional(self: Type) bool {1978 pub fn isPtrLikeOptional(self: Type) bool {
1917 switch (self.tag()) {1979 switch (self.tag()) {
1918 .optional_single_const_pointer, .optional_single_mut_pointer => return true,1980 .optional_single_const_pointer,
1981 .optional_single_mut_pointer,
1982 => return true,
1983
1919 .optional => {1984 .optional => {
1920 var buf: Payload.ElemType = undefined;1985 var buf: Payload.ElemType = undefined;
1921 const child_type = self.optionalChild(&buf);1986 const child_type = self.optionalChild(&buf);
...@@ -2400,6 +2465,7 @@ pub const Type = extern union {...@@ -2400,6 +2465,7 @@ pub const Type = extern union {
2400 .error_union,2465 .error_union,
2401 .error_set,2466 .error_set,
2402 .error_set_single,2467 .error_set_single,
2468 .error_set_inferred,
2403 .@"opaque",2469 .@"opaque",
2404 .var_args_param,2470 .var_args_param,
2405 .manyptr_u8,2471 .manyptr_u8,
...@@ -2892,6 +2958,8 @@ pub const Type = extern union {...@@ -2892,6 +2958,8 @@ pub const Type = extern union {
2892 anyframe_T,2958 anyframe_T,
2893 error_set,2959 error_set,
2894 error_set_single,2960 error_set_single,
2961 /// The type is the inferred error set of a specific function.
2962 error_set_inferred,
2895 empty_struct,2963 empty_struct,
2896 @"opaque",2964 @"opaque",
2897 @"struct",2965 @"struct",
...@@ -2989,6 +3057,7 @@ pub const Type = extern union {...@@ -2989,6 +3057,7 @@ pub const Type = extern union {
2989 => Payload.Bits,3057 => Payload.Bits,
29903058
2991 .error_set => Payload.ErrorSet,3059 .error_set => Payload.ErrorSet,
3060 .error_set_inferred => Payload.ErrorSetInferred,
29923061
2993 .array, .vector => Payload.Array,3062 .array, .vector => Payload.Array,
2994 .array_sentinel => Payload.ArraySentinel,3063 .array_sentinel => Payload.ArraySentinel,
...@@ -3081,6 +3150,13 @@ pub const Type = extern union {...@@ -3081,6 +3150,13 @@ pub const Type = extern union {
3081 data: *Module.ErrorSet,3150 data: *Module.ErrorSet,
3082 };3151 };
30833152
3153 pub const ErrorSetInferred = struct {
3154 pub const base_tag = Tag.error_set_inferred;
3155
3156 base: Payload = Payload{ .tag = base_tag },
3157 data: *Module.Fn,
3158 };
3159
3084 pub const Pointer = struct {3160 pub const Pointer = struct {
3085 pub const base_tag = Tag.pointer;3161 pub const base_tag = Tag.pointer;
30863162
src/value.zig+22-5
...@@ -483,13 +483,13 @@ pub const Value = extern union {...@@ -483,13 +483,13 @@ pub const Value = extern union {
483 /// TODO this should become a debug dump() function. In order to print values in a meaningful way483 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
484 /// we also need access to the type.484 /// we also need access to the type.
485 pub fn format(485 pub fn format(
486 self: Value,486 start_val: Value,
487 comptime fmt: []const u8,487 comptime fmt: []const u8,
488 options: std.fmt.FormatOptions,488 options: std.fmt.FormatOptions,
489 out_stream: anytype,489 out_stream: anytype,
490 ) !void {490 ) !void {
491 comptime assert(fmt.len == 0);491 comptime assert(fmt.len == 0);
492 var val = self;492 var val = start_val;
493 while (true) switch (val.tag()) {493 while (true) switch (val.tag()) {
494 .u8_type => return out_stream.writeAll("u8"),494 .u8_type => return out_stream.writeAll("u8"),
495 .i8_type => return out_stream.writeAll("i8"),495 .i8_type => return out_stream.writeAll("i8"),
...@@ -598,9 +598,9 @@ pub const Value = extern union {...@@ -598,9 +598,9 @@ pub const Value = extern union {
598 val = field_ptr.container_ptr;598 val = field_ptr.container_ptr;
599 },599 },
600 .empty_array => return out_stream.writeAll(".{}"),600 .empty_array => return out_stream.writeAll(".{}"),
601 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),601 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
602 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),602 .enum_field_index => return out_stream.print("(enum field {d})", .{val.castTag(.enum_field_index).?.data}),
603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
604 .repeated => {604 .repeated => {
605 try out_stream.writeAll("(repeated) ");605 try out_stream.writeAll("(repeated) ");
606 val = val.castTag(.repeated).?.data;606 val = val.castTag(.repeated).?.data;
...@@ -1336,6 +1336,23 @@ pub const Value = extern union {...@@ -1336,6 +1336,23 @@ pub const Value = extern union {
1336 };1336 };
1337 }1337 }
13381338
1339 pub fn sliceLen(val: Value) u64 {
1340 return switch (val.tag()) {
1341 .empty_array => 0,
1342 .bytes => val.castTag(.bytes).?.data.len,
1343 .ref_val => sliceLen(val.castTag(.ref_val).?.data),
1344 .decl_ref => {
1345 const decl = val.castTag(.decl_ref).?.data;
1346 if (decl.ty.zigTypeTag() == .Array) {
1347 return decl.ty.arrayLen();
1348 } else {
1349 return 1;
1350 }
1351 },
1352 else => unreachable,
1353 };
1354 }
1355
1339 /// Asserts the value is a single-item pointer to an array, or an array,1356 /// Asserts the value is a single-item pointer to an array, or an array,
1340 /// or an unknown-length pointer, and returns the element value at the index.1357 /// or an unknown-length pointer, and returns the element value at the index.
1341 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {1358 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
test/stage2/cbe.zig-13
...@@ -804,19 +804,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -804,19 +804,6 @@ pub fn addCases(ctx: *TestContext) !void {
804 });804 });
805 }805 }
806806
807 ctx.c("empty start function", linux_x64,
808 \\export fn _start() noreturn {
809 \\ unreachable;
810 \\}
811 ,
812 \\ZIG_EXTERN_C zig_noreturn void _start(void);
813 \\
814 \\zig_noreturn void _start(void) {
815 \\ zig_breakpoint();
816 \\ zig_unreachable();
817 \\}
818 \\
819 );
820 ctx.h("simple header", linux_x64,807 ctx.h("simple header", linux_x64,
821 \\export fn start() void{}808 \\export fn start() void{}
822 ,809 ,