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
18601860 }
18611861 }
18621862
1863 try genDefers(gz, parent_scope, scope, .none);
1863 try genDefers(gz, parent_scope, scope, .normal_only);
18641864 try checkUsed(gz, parent_scope, scope);
18651865}
18661866
......@@ -2102,6 +2102,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
21022102 .@"resume",
21032103 .@"await",
21042104 .await_nosuspend,
2105 .ret_err_value_code,
21052106 .extended,
21062107 => break :b false,
21072108
......@@ -2113,6 +2114,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
21132114 .compile_error,
21142115 .ret_node,
21152116 .ret_coerce,
2117 .ret_err_value,
21162118 .@"unreachable",
21172119 .repeat,
21182120 .repeat_inline,
......@@ -2162,13 +2164,63 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
21622164 return noreturn_src_node;
21632165}
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
21652218fn genDefers(
21662219 gz: *GenZir,
21672220 outer_scope: *Scope,
21682221 inner_scope: *Scope,
2169 err_code: Zir.Inst.Ref,
2222 which_ones: DefersToEmit,
21702223) InnerError!void {
2171 _ = err_code;
21722224 const astgen = gz.astgen;
21732225 const tree = astgen.tree;
21742226 const node_datas = tree.nodes.items(.data);
......@@ -2191,12 +2243,37 @@ fn genDefers(
21912243 .defer_error => {
21922244 const defer_scope = scope.cast(Scope.Defer).?;
21932245 scope = defer_scope.parent;
2194 if (err_code == .none) continue;
2195 const expr_node = node_datas[defer_scope.defer_node].rhs;
2196 const prev_in_defer = gz.in_defer;
2197 gz.in_defer = true;
2198 defer gz.in_defer = prev_in_defer;
2199 _ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
2246 switch (which_ones) {
2247 .both_sans_err => {
2248 const expr_node = node_datas[defer_scope.defer_node].rhs;
2249 const prev_in_defer = gz.in_defer;
2250 gz.in_defer = true;
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 }
22002277 },
22012278 .namespace => unreachable,
22022279 .top => unreachable,
......@@ -4564,7 +4641,7 @@ fn tryExpr(
45644641 defer then_scope.instructions.deinit(astgen.gpa);
45654642
45664643 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 });
45684645 const then_result = try then_scope.addUnNode(.ret_node, err_code, node);
45694646
45704647 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
60906167 const astgen = gz.astgen;
60916168 const tree = astgen.tree;
60926169 const node_datas = tree.nodes.items(.data);
6170 const node_tags = tree.nodes.items(.tag);
60936171
60946172 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
60956173
6174 const defer_outer = &astgen.fn_block.?.base;
6175
60966176 const operand_node = node_datas[node].lhs;
60976177 if (operand_node == 0) {
60986178 // 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);
61006180 _ = try gz.addUnNode(.ret_node, .void_value, node);
61016181 return Zir.Inst.Ref.unreachable_value;
61026182 }
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
61046201 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{
61056202 .ptr = try gz.addNodeExtended(.ret_ptr, node),
61066203 } else .{
......@@ -6111,31 +6208,41 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
61116208 switch (nodeMayEvalToError(tree, operand_node)) {
61126209 .never => {
61136210 // 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);
61156212 _ = try gz.addUnNode(.ret_node, operand, node);
61166213 return Zir.Inst.Ref.unreachable_value;
61176214 },
61186215 .always => {
61196216 // Value is always an error. Emit both error defers and regular defers.
61206217 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 });
61226219 _ = try gz.addUnNode(.ret_node, operand, node);
61236220 return Zir.Inst.Ref.unreachable_value;
61246221 },
61256222 .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
61266231 // Emit conditional branch for generating errdefers.
61276232 const is_err = try gz.addUnNode(.is_err, operand, node);
61286233 const condbr = try gz.addCondBr(.condbr, node);
61296234
61306235 var then_scope = gz.makeSubBlock(scope);
61316236 defer then_scope.instructions.deinit(astgen.gpa);
6132 const err_code = try then_scope.addUnNode(.err_union_code, operand, node);
6133 try genDefers(&then_scope, &astgen.fn_block.?.base, scope, err_code);
6237 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
6238 .both = try then_scope.addUnNode(.err_union_code, operand, node),
6239 };
6240 try genDefers(&then_scope, defer_outer, scope, which_ones);
61346241 _ = try then_scope.addUnNode(.ret_node, operand, node);
61356242
61366243 var else_scope = gz.makeSubBlock(scope);
61376244 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);
61396246 _ = try else_scope.addUnNode(.ret_node, operand, node);
61406247
61416248 try setCondBrPayload(condbr, is_err, &then_scope, &else_scope);
......@@ -6885,7 +6992,7 @@ fn builtinCall(
68856992 .field => {
68866993 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
68876994 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{
68896996 .lhs = try expr(gz, scope, .ref, params[0]),
68906997 .field_name = field_name,
68916998 });
src/Module.zig+4
......@@ -755,6 +755,7 @@ pub const Fn = struct {
755755 rbrace_column: u16,
756756
757757 state: Analysis,
758 is_cold: bool = false,
758759
759760 pub const Analysis = enum {
760761 queued,
......@@ -3453,6 +3454,9 @@ pub fn clearDecl(
34533454 for (decl.dependencies.keys()) |dep| {
34543455 dep.removeDependant(decl);
34553456 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 });
34563460 // We don't recursively perform a deletion here, because during the update,
34573461 // another reference to it may turn up.
34583462 dep.deletion_flag = true;
src/Sema.zig+148-63
......@@ -244,6 +244,7 @@ pub fn analyzeBody(
244244 .ptr_type => try sema.zirPtrType(block, inst),
245245 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
246246 .ref => try sema.zirRef(block, inst),
247 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
247248 .shl => try sema.zirShl(block, inst),
248249 .shr => try sema.zirShr(block, inst),
249250 .slice_end => try sema.zirSliceEnd(block, inst),
......@@ -380,8 +381,9 @@ pub fn analyzeBody(
380381 .condbr => return sema.zirCondbr(block, inst),
381382 .@"break" => return sema.zirBreak(block, inst),
382383 .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),
384385 .ret_node => return sema.zirRetNode(block, inst),
386 .ret_err_value => return sema.zirRetErrValue(block, inst),
385387 .@"unreachable" => return sema.zirUnreachable(block, inst),
386388 .repeat => return sema.zirRepeat(block, inst),
387389 .panic => return sema.zirPanic(block, inst),
......@@ -587,6 +589,19 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!*ir.In
587589 return sema.inst_map.get(@intCast(u32, i)).?;
588590}
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
590605fn resolveConstString(
591606 sema: *Sema,
592607 block: *Scope.Block,
......@@ -1754,8 +1769,9 @@ fn zirRepeat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
17541769fn zirPanic(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Zir.Inst.Index {
17551770 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17561771 const src: LazySrcLoc = inst_data.src();
1757 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirPanic", .{});
1758 //return always_noreturn;
1772 const msg_inst = try sema.resolveInst(inst_data.operand);
1773
1774 return sema.panicWithMsg(block, src, msg_inst);
17591775}
17601776
17611777fn 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
20282044
20292045fn zirSetCold(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
20302046 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2031 const src: LazySrcLoc = inst_data.src();
2032 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirSetCold", .{});
2047 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
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;
20332051}
20342052
20352053fn 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
20412059fn zirSetRuntimeSafety(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
20422060 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
20432061 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2044
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;
2062 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand);
20492063}
20502064
20512065fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void {
......@@ -2190,21 +2204,27 @@ fn zirCall(
21902204 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
21912205 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);
21942216}
21952217
21962218fn analyzeCall(
21972219 sema: *Sema,
21982220 block: *Scope.Block,
2199 zir_func: Zir.Inst.Ref,
2221 func: *ir.Inst,
22002222 func_src: LazySrcLoc,
22012223 call_src: LazySrcLoc,
22022224 modifier: std.builtin.CallOptions.Modifier,
22032225 ensure_result_used: bool,
2204 zir_args: []const Zir.Inst.Ref,
2226 args: []const *ir.Inst,
22052227) InnerError!*ir.Inst {
2206 const func = try sema.resolveInst(zir_func);
2207
22082228 if (func.ty.zigTypeTag() != .Fn)
22092229 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
22102230
......@@ -2221,22 +2241,22 @@ fn analyzeCall(
22212241 const fn_params_len = func.ty.fnParamLen();
22222242 if (func.ty.fnIsVarArgs()) {
22232243 assert(cc == .C);
2224 if (zir_args.len < fn_params_len) {
2244 if (args.len < fn_params_len) {
22252245 // TODO add error note: declared here
22262246 return sema.mod.fail(
22272247 &block.base,
22282248 func_src,
22292249 "expected at least {d} argument(s), found {d}",
2230 .{ fn_params_len, zir_args.len },
2250 .{ fn_params_len, args.len },
22312251 );
22322252 }
2233 } else if (fn_params_len != zir_args.len) {
2253 } else if (fn_params_len != args.len) {
22342254 // TODO add error note: declared here
22352255 return sema.mod.fail(
22362256 &block.base,
22372257 func_src,
22382258 "expected {d} argument(s), found {d}",
2239 .{ fn_params_len, zir_args.len },
2259 .{ fn_params_len, args.len },
22402260 );
22412261 }
22422262
......@@ -2256,13 +2276,6 @@ fn analyzeCall(
22562276 }),
22572277 }
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
22662279 const ret_type = func.ty.fnReturnType();
22672280
22682281 const is_comptime_call = block.is_comptime or modifier == .compile_time;
......@@ -2323,7 +2336,7 @@ fn analyzeCall(
23232336 defer sema.func = parent_func;
23242337
23252338 const parent_param_inst_list = sema.param_inst_list;
2326 sema.param_inst_list = casted_args;
2339 sema.param_inst_list = args;
23272340 defer sema.param_inst_list = parent_param_inst_list;
23282341
23292342 const parent_next_arg_index = sema.next_arg_index;
......@@ -2357,7 +2370,7 @@ fn analyzeCall(
23572370 break :res result;
23582371 } else res: {
23592372 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);
23612374 };
23622375
23632376 if (ensure_result_used) {
......@@ -3081,28 +3094,31 @@ fn funcCommon(
30813094) InnerError!*Inst {
30823095 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
30833096 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
30863099 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
30883104 const fn_ty: Type = fn_ty: {
30893105 // Hot path for some common function types.
30903106 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and
30913107 !inferred_error_set)
30923108 {
3093 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
3109 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
30943110 break :fn_ty Type.initTag(.fn_noreturn_no_args);
30953111 }
30963112
3097 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {
3113 if (bare_return_type.zigTypeTag() == .Void and cc == .Unspecified) {
30983114 break :fn_ty Type.initTag(.fn_void_no_args);
30993115 }
31003116
3101 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
3117 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
31023118 break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
31033119 }
31043120
3105 if (return_type.zigTypeTag() == .Void and cc == .C) {
3121 if (bare_return_type.zigTypeTag() == .Void and cc == .C) {
31063122 break :fn_ty Type.initTag(.fn_ccc_void_no_args);
31073123 }
31083124 }
......@@ -3120,9 +3136,13 @@ fn funcCommon(
31203136 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
31213137 }
31223138
3123 if (inferred_error_set) {
3124 return mod.fail(&block.base, src, "TODO implement functions with inferred error sets", .{});
3125 }
3139 const return_type = if (!inferred_error_set) bare_return_type else blk: {
3140 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, new_func);
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
31273147 break :fn_ty try Type.Tag.function.create(sema.arena, .{
31283148 .param_types = param_types,
......@@ -3188,7 +3208,6 @@ fn funcCommon(
31883208 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
31893209
31903210 const fn_payload = try sema.arena.create(Value.Payload.Function);
3191 const new_func = try sema.gpa.create(Module.Fn);
31923211 new_func.* = .{
31933212 .state = anal_state,
31943213 .zir_body_inst = body_inst,
......@@ -4542,6 +4561,12 @@ fn zirImport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!
45424561 return mod.constType(sema.arena, src, file_root_decl.ty);
45434562}
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
45454570fn zirShl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
45464571 const tracy = trace(@src());
45474572 defer tracy.end();
......@@ -5388,7 +5413,24 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE
53885413 }
53895414}
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(
53925434 sema: *Sema,
53935435 block: *Scope.Block,
53945436 inst: Zir.Inst.Index,
......@@ -6195,6 +6237,10 @@ fn zirFuncExtended(
61956237 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
61966238 }
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
61986244 return sema.funcCommon(
61996245 block,
62006246 extra.data.src_node,
......@@ -6203,9 +6249,9 @@ fn zirFuncExtended(
62036249 extra.data.return_type,
62046250 cc,
62056251 align_val,
6206 small.is_var_args,
6207 small.is_inferred_error,
6208 small.is_extern,
6252 is_var_args,
6253 is_inferred_error,
6254 is_extern,
62096255 src_locs,
62106256 lib_name,
62116257 );
......@@ -6357,15 +6403,51 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:
63576403 try parent_block.instructions.append(sema.gpa, &block_inst.base);
63586404}
63596405
6360fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !Zir.Inst.Index {
6361 _ = sema;
6362 _ = panic_id;
6363 // TODO Once we have a panic function to call, call it here instead of breakpoint.
6364 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
6365 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
6406fn panicWithMsg(
6407 sema: *Sema,
6408 block: *Scope.Block,
6409 src: LazySrcLoc,
6410 msg_inst: *ir.Inst,
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);
63666425 return always_noreturn;
63676426}
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
63696451fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
63706452 sema.branch_count += 1;
63716453 if (sema.branch_count > sema.branch_quota) {
......@@ -7377,15 +7459,13 @@ fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst)
73777459}
73787460
73797461fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
7380 // TODO deal with inferred error sets
73817462 const err_union = dest_type.castTag(.error_union).?;
73827463 if (inst.value()) |val| {
7383 const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {
7464 if (inst.ty.zigTypeTag() != .ErrorSet) {
73847465 _ = try sema.coerce(block, err_union.data.payload, inst, inst.src);
7385 break :blk val;
73867466 } else switch (err_union.data.error_set.tag()) {
7387 .anyerror => val,
7388 .error_set_single => blk: {
7467 .anyerror => {},
7468 .error_set_single => {
73897469 const expected_name = val.castTag(.@"error").?.data.name;
73907470 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
73917471 if (!mem.eql(u8, expected_name, n)) {
......@@ -7396,9 +7476,8 @@ fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst
73967476 .{ err_union.data.error_set, inst.ty },
73977477 );
73987478 }
7399 break :blk val;
74007479 },
7401 .error_set => blk: {
7480 .error_set => {
74027481 const expected_name = val.castTag(.@"error").?.data.name;
74037482 const error_set = err_union.data.error_set.castTag(.error_set).?.data;
74047483 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
74157494 .{ err_union.data.error_set, inst.ty },
74167495 );
74177496 }
7418 break :blk val;
74197497 },
74207498 else => unreachable,
7421 };
7499 }
74227500
74237501 return sema.mod.constInst(sema.arena, inst.src, .{
74247502 .ty = dest_type,
74257503 // creating a SubValue for the error_union payload
7426 .val = try Value.Tag.error_union.create(
7427 sema.arena,
7428 to_wrap,
7429 ),
7504 .val = try Value.Tag.error_union.create(sema.arena, val),
74307505 });
74317506 }
74327507
......@@ -7573,12 +7648,12 @@ fn resolveBuiltinTypeFields(
75737648 return sema.resolveTypeFields(block, src, resolved_ty);
75747649}
75757650
7576fn getBuiltinType(
7651fn getBuiltin(
75777652 sema: *Sema,
75787653 block: *Scope.Block,
75797654 src: LazySrcLoc,
75807655 name: []const u8,
7581) InnerError!Type {
7656) InnerError!*ir.Inst {
75827657 const mod = sema.mod;
75837658 const std_pkg = mod.root_pkg.table.get("std").?;
75847659 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
......@@ -7596,7 +7671,16 @@ fn getBuiltinType(
75967671 builtin_ty.getNamespace().?,
75977672 name,
75987673 );
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);
76007684 return sema.resolveAirAsType(block, src, ty_inst);
76017685}
76027686
......@@ -7662,6 +7746,7 @@ fn typeHasOnePossibleValue(
76627746 .error_union,
76637747 .error_set,
76647748 .error_set_single,
7749 .error_set_inferred,
76657750 .@"opaque",
76667751 .var_args_param,
76677752 .manyptr_u8,
src/Zir.zig+23-4
......@@ -1,7 +1,7 @@
11//! 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.
33//! 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 by
4//! Once this structure is completed, it can be used to generate AIR, followed by
55//! machine code, without any memory access into the AST tree token list, node list,
66//! or source bytes. Exceptions include:
77//! * Compile errors, which may need to reach into these data structures to
......@@ -416,8 +416,8 @@ pub const Inst = struct {
416416 /// A labeled block of code that loops forever. At the end of the body will have either
417417 /// a `repeat` instruction or a `repeat_inline` instruction.
418418 /// 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 Sema
420 /// needs to emit more than 1 TZIR block for this instruction.
419 /// This ZIR instruction is needed because AIR does not (yet?) match ZIR, and Sema
420 /// needs to emit more than 1 AIR block for this instruction.
421421 /// The payload is `Block`.
422422 loop,
423423 /// Sends runtime control flow back to the beginning of the current block.
......@@ -466,6 +466,19 @@ pub const Inst = struct {
466466 /// Uses the `un_tok` union field.
467467 /// The operand needs to get coerced to the function's return type.
468468 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,
469482 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
470483 /// Uses the `ptr_type_simple` union field.
471484 ptr_type_simple,
......@@ -1193,6 +1206,7 @@ pub const Inst = struct {
11931206 .@"resume",
11941207 .@"await",
11951208 .await_nosuspend,
1209 .ret_err_value_code,
11961210 .extended,
11971211 => false,
11981212
......@@ -1203,6 +1217,7 @@ pub const Inst = struct {
12031217 .compile_error,
12041218 .ret_node,
12051219 .ret_coerce,
1220 .ret_err_value,
12061221 .@"unreachable",
12071222 .repeat,
12081223 .repeat_inline,
......@@ -1307,6 +1322,8 @@ pub const Inst = struct {
13071322 .ref = .un_tok,
13081323 .ret_node = .un_node,
13091324 .ret_coerce = .un_tok,
1325 .ret_err_value = .str_tok,
1326 .ret_err_value_code = .str_tok,
13101327 .ptr_type_simple = .ptr_type_simple,
13111328 .ptr_type = .ptr_type,
13121329 .slice_start = .pl_node,
......@@ -3077,6 +3094,8 @@ const Writer = struct {
30773094 .decl_val,
30783095 .import,
30793096 .arg,
3097 .ret_err_value,
3098 .ret_err_value_code,
30803099 => try self.writeStrTok(stream, inst),
30813100
30823101 .func => try self.writeFunc(stream, inst, false),
src/air.zig+11-11
......@@ -672,15 +672,15 @@ pub const Body = struct {
672672/// For debugging purposes, prints a function representation to stderr.
673673pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
674674 const allocator = old_module.gpa;
675 var ctx: DumpTzir = .{
675 var ctx: DumpAir = .{
676676 .allocator = allocator,
677677 .arena = std.heap.ArenaAllocator.init(allocator),
678678 .old_module = &old_module,
679679 .module_fn = module_fn,
680680 .indent = 2,
681 .inst_table = DumpTzir.InstTable.init(allocator),
682 .partial_inst_table = DumpTzir.InstTable.init(allocator),
683 .const_table = DumpTzir.InstTable.init(allocator),
681 .inst_table = DumpAir.InstTable.init(allocator),
682 .partial_inst_table = DumpAir.InstTable.init(allocator),
683 .const_table = DumpAir.InstTable.init(allocator),
684684 };
685685 defer ctx.inst_table.deinit();
686686 defer ctx.partial_inst_table.deinit();
......@@ -695,12 +695,12 @@ pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void {
695695 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
696696 .success => {
697697 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");
699699 },
700700 }
701701}
702702
703const DumpTzir = struct {
703const DumpAir = struct {
704704 allocator: *std.mem.Allocator,
705705 arena: std.heap.ArenaAllocator,
706706 old_module: *const Module,
......@@ -718,7 +718,7 @@ const DumpTzir = struct {
718718 /// TODO: Improve this code to include a stack of Body and store the instructions
719719 /// in there. Now we are putting all the instructions in a function local table,
720720 /// 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 {
722722 // First pass to pre-populate the table so that we can show even invalid references.
723723 // Must iterate the same order we iterate the second time.
724724 // We also look for constants and put them in the const_table.
......@@ -737,7 +737,7 @@ const DumpTzir = struct {
737737 return dtz.dumpBody(body, writer);
738738 }
739739
740 fn fetchInstsAndResolveConsts(dtz: *DumpTzir, body: Body) error{OutOfMemory}!void {
740 fn fetchInstsAndResolveConsts(dtz: *DumpAir, body: Body) error{OutOfMemory}!void {
741741 for (body.instructions) |inst| {
742742 try dtz.inst_table.put(inst, dtz.next_index);
743743 dtz.next_index += 1;
......@@ -865,7 +865,7 @@ const DumpTzir = struct {
865865 }
866866 }
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 {
869869 for (body.instructions) |inst| {
870870 const my_index = dtz.next_partial_index;
871871 try dtz.partial_inst_table.put(inst, my_index);
......@@ -1150,7 +1150,7 @@ const DumpTzir = struct {
11501150 }
11511151 }
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 {
11541154 if (dtz.partial_inst_table.get(inst)) |operand_index| {
11551155 try writer.print("%{d}", .{operand_index});
11561156 return null;
......@@ -1166,7 +1166,7 @@ const DumpTzir = struct {
11661166 }
11671167 }
11681168
1169 fn findConst(dtz: *DumpTzir, operand: *Inst) !void {
1169 fn findConst(dtz: *DumpAir, operand: *Inst) !void {
11701170 if (operand.tag == .constant) {
11711171 try dtz.const_table.put(operand, dtz.next_const_index);
11721172 dtz.next_const_index += 1;
src/codegen/c.zig+229-60
......@@ -39,7 +39,12 @@ const BlockData = struct {
3939};
4040
4141pub 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
4449fn formatTypeAsCIdentifier(
4550 data: Type,
......@@ -151,14 +156,49 @@ pub const Object = struct {
151156 render_ty = render_ty.elemType();
152157 }
153158
154 try o.dg.renderType(w, render_ty);
155
156 const const_prefix = switch (mutability) {
157 .Const => "const ",
158 .Mut => "",
159 };
160 try w.print(" {s}", .{const_prefix});
161 try o.writeCValue(w, name);
159 if (render_ty.zigTypeTag() == .Fn) {
160 const ret_ty = render_ty.fnReturnType();
161 if (ret_ty.zigTypeTag() == .NoReturn) {
162 // noreturn attribute is not allowed here.
163 try w.writeAll("void");
164 } else {
165 try o.dg.renderType(w, ret_ty);
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 }
162202 try w.writeAll(suffix.items);
163203 }
164204};
......@@ -196,35 +236,72 @@ pub const DeclGen = struct {
196236 return writer.print("{d}", .{val.toSignedInt()});
197237 return writer.print("{d}", .{val.toUnsignedInt()});
198238 },
199 .Pointer => switch (val.tag()) {
200 .null_value, .zero => try writer.writeAll("NULL"),
201 .one => try writer.writeAll("1"),
202 .decl_ref => {
203 const decl = val.castTag(.decl_ref).?.data;
204
205 // Determine if we must pointer cast.
206 assert(decl.has_tv);
207 if (t.eql(decl.ty)) {
208 try writer.print("&{s}", .{decl.name});
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});
239 .Pointer => switch (t.ptrSize()) {
240 .Slice => {
241 try writer.writeByte('(');
242 try dg.renderType(writer, t);
243 try writer.writeAll("){");
244 var buf: Type.Payload.ElemType = undefined;
245 try dg.renderValue(writer, t.slicePtrFieldType(&buf), val);
246 try writer.writeAll(", ");
247 try writer.print("{d}", .{val.sliceLen()});
248 try writer.writeAll("}");
218249 },
219 .extern_fn => {
220 const decl = val.castTag(.extern_fn).?.data;
221 try writer.print("{s}", .{decl.name});
250 else => switch (val.tag()) {
251 .null_value, .zero => try writer.writeAll("NULL"),
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 },
222304 },
223 else => |e| return dg.fail(
224 .{ .node_offset = 0 },
225 "TODO: C backend: implement Pointer value {s}",
226 .{@tagName(e)},
227 ),
228305 },
229306 .Array => {
230307 // First try specific tag representations for more efficiency.
......@@ -329,6 +406,32 @@ pub const DeclGen = struct {
329406 },
330407 }
331408 },
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 },
332435 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
333436 @tagName(e),
334437 }),
......@@ -339,6 +442,12 @@ pub const DeclGen = struct {
339442 if (!is_global) {
340443 try w.writeAll("static ");
341444 }
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 }
342451 try dg.renderType(w, dg.decl.ty.fnReturnType());
343452 const decl_name = mem.span(dg.decl.name);
344453 try w.print(" {s}(", .{decl_name});
......@@ -413,7 +522,35 @@ pub const DeclGen = struct {
413522
414523 .Pointer => {
415524 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 });
417554 } else {
418555 try dg.renderType(w, t.elemType());
419556 try w.writeAll(" *");
......@@ -446,13 +583,13 @@ pub const DeclGen = struct {
446583 try dg.renderType(bw, child_type);
447584 try bw.writeAll(" payload; bool is_null; } ");
448585 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
451588 const rendered = buffer.toOwnedSlice();
452589 errdefer dg.typedefs.allocator.free(rendered);
453590 const name = rendered[name_index .. rendered.len - 2];
454591
455 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);
592 try dg.typedefs.ensureUnusedCapacity(1);
456593 try w.writeAll(name);
457594 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
458595 },
......@@ -465,7 +602,7 @@ pub const DeclGen = struct {
465602 return w.writeAll(some.name);
466603 }
467604 const child_type = t.errorUnionChild();
468 const set_type = t.errorUnionSet();
605 const err_set_type = t.errorUnionSet();
469606
470607 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
471608 defer buffer.deinit();
......@@ -475,13 +612,20 @@ pub const DeclGen = struct {
475612 try dg.renderType(bw, child_type);
476613 try bw.writeAll(" payload; uint16_t error; } ");
477614 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
480624 const rendered = buffer.toOwnedSlice();
481625 errdefer dg.typedefs.allocator.free(rendered);
482626 const name = rendered[name_index .. rendered.len - 2];
483627
484 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);
628 try dg.typedefs.ensureUnusedCapacity(1);
485629 try w.writeAll(name);
486630 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
487631 },
......@@ -514,7 +658,7 @@ pub const DeclGen = struct {
514658 errdefer dg.typedefs.allocator.free(rendered);
515659 const name = rendered[name_start .. rendered.len - 2];
516660
517 try dg.typedefs.ensureCapacity(dg.typedefs.capacity() + 1);
661 try dg.typedefs.ensureUnusedCapacity(1);
518662 try w.writeAll(name);
519663 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
520664 },
......@@ -526,7 +670,28 @@ pub const DeclGen = struct {
526670 try dg.renderType(w, int_tag_ty);
527671 },
528672 .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 },
530695 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),
531696 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),
532697 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),
......@@ -569,23 +734,27 @@ pub fn genDecl(o: *Object) !void {
569734 .val = o.dg.decl.val,
570735 };
571736 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
580737 const func: *Module.Fn = func_payload.data;
581 try o.indent_writer.insertNewline();
582 try o.dg.renderFunctionSignature(o.writer(), is_global);
738 if (func.owner_decl == o.dg.decl) {
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(' ');
585 try genBody(o, func.body);
747 try o.indent_writer.insertNewline();
748 try o.dg.renderFunctionSignature(o.writer(), is_global);
586749
587 try o.indent_writer.insertNewline();
588 } else if (tv.val.tag() == .extern_fn) {
750 try o.writer().writeByte(' ');
751 try genBody(o, func.body);
752
753 try o.indent_writer.insertNewline();
754 return;
755 }
756 }
757 if (tv.val.tag() == .extern_fn) {
589758 const writer = o.writer();
590759 try writer.writeAll("ZIG_EXTERN_C ");
591760 try o.dg.renderFunctionSignature(writer, true);
......@@ -644,9 +813,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
644813 const is_global = dg.declIsGlobal(tv);
645814 if (is_global) {
646815 try writer.writeAll("ZIG_EXTERN_C ");
816 try dg.renderFunctionSignature(writer, is_global);
817 try dg.fwd_decl.appendSlice(";\n");
647818 }
648 try dg.renderFunctionSignature(writer, is_global);
649 try dg.fwd_decl.appendSlice(";\n");
650819 },
651820 else => {},
652821 }
src/link/C.zig+4-6
......@@ -207,7 +207,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
207207 }
208208
209209 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);
211211 defer typedefs.deinit();
212212
213213 // Typedefs, forward decls and non-functions first.
......@@ -217,14 +217,12 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
217217 if (!decl.has_tv) continue;
218218 const buf = buf: {
219219 if (decl.val.castTag(.function)) |_| {
220 try typedefs.ensureUnusedCapacity(decl.fn_link.c.typedefs.count());
220221 var it = decl.fn_link.c.typedefs.iterator();
221222 while (it.next()) |new| {
222 if (typedefs.get(new.key_ptr.*)) |previous| {
223 try err_typedef_writer.print("typedef {s} {s};\n", .{ previous, new.value_ptr.name });
224 } else {
225 try typedefs.ensureCapacity(typedefs.capacity() + 1);
223 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
224 if (!gop.found_existing) {
226225 try err_typedef_writer.writeAll(new.value_ptr.rendered);
227 typedefs.putAssumeCapacityNoClobber(new.key_ptr.*, new.value_ptr.name);
228226 }
229227 }
230228 fn_count += 1;
src/link/C/zig.h+6
......@@ -12,6 +12,12 @@
1212#define zig_threadlocal zig_threadlocal_unavailable
1313#endif
1414
15#if __GNUC__
16#define ZIG_COLD __attribute__ ((cold))
17#else
18#define ZIG_COLD
19#endif
20
1521#if __STDC_VERSION__ >= 199901L
1622#define ZIG_RESTRICT restrict
1723#elif defined(__GNUC__)
src/type.zig+79-3
......@@ -58,7 +58,7 @@ pub const Type = extern union {
5858 .bool => return .Bool,
5959 .void => return .Void,
6060 .type => return .Type,
61 .error_set, .error_set_single, .anyerror => return .ErrorSet,
61 .error_set, .error_set_single, .anyerror, .error_set_inferred => return .ErrorSet,
6262 .comptime_int => return .ComptimeInt,
6363 .comptime_float => return .ComptimeFloat,
6464 .noreturn => return .NoReturn,
......@@ -689,7 +689,15 @@ pub const Type = extern union {
689689 .optional_single_mut_pointer,
690690 .optional_single_const_pointer,
691691 .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
694702 .int_signed,
695703 .int_unsigned,
......@@ -756,6 +764,7 @@ pub const Type = extern union {
756764 });
757765 },
758766 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
767 .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred),
759768 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
760769 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
761770 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
......@@ -1031,6 +1040,10 @@ pub const Type = extern union {
10311040 const error_set = ty.castTag(.error_set).?.data;
10321041 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
10331042 },
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 },
10341047 .error_set_single => {
10351048 const name = ty.castTag(.error_set_single).?.data;
10361049 return writer.print("error{{{s}}}", .{name});
......@@ -1144,6 +1157,7 @@ pub const Type = extern union {
11441157 .anyerror_void_error_union,
11451158 .error_set,
11461159 .error_set_single,
1160 .error_set_inferred,
11471161 .manyptr_u8,
11481162 .manyptr_const_u8,
11491163 .atomic_ordering,
......@@ -1161,6 +1175,9 @@ pub const Type = extern union {
11611175 .@"struct" => {
11621176 // TODO introduce lazy value mechanism
11631177 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);
11641181 for (struct_obj.fields.values()) |value| {
11651182 if (value.ty.hasCodeGenBits())
11661183 return true;
......@@ -1348,6 +1365,7 @@ pub const Type = extern union {
13481365 .error_set_single,
13491366 .anyerror_void_error_union,
13501367 .anyerror,
1368 .error_set_inferred,
13511369 => return 2, // TODO revisit this when we have the concept of the error tag type
13521370
13531371 .array, .array_sentinel => return self.elemType().abiAlignment(target),
......@@ -1580,6 +1598,7 @@ pub const Type = extern union {
15801598 .error_set_single,
15811599 .anyerror_void_error_union,
15821600 .anyerror,
1601 .error_set_inferred,
15831602 => return 2, // TODO revisit this when we have the concept of the error tag type
15841603
15851604 .int_signed, .int_unsigned => {
......@@ -1744,6 +1763,7 @@ pub const Type = extern union {
17441763 .error_set_single,
17451764 .anyerror_void_error_union,
17461765 .anyerror,
1766 .error_set_inferred,
17471767 => return 16, // TODO revisit this when we have the concept of the error tag type
17481768
17491769 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
......@@ -1863,6 +1883,48 @@ pub const Type = extern union {
18631883 };
18641884 }
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
18661928 pub fn isConstPtr(self: Type) bool {
18671929 return switch (self.tag()) {
18681930 .single_const_pointer,
......@@ -1915,7 +1977,10 @@ pub const Type = extern union {
19151977 /// Asserts that the type is an optional
19161978 pub fn isPtrLikeOptional(self: Type) bool {
19171979 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
19191984 .optional => {
19201985 var buf: Payload.ElemType = undefined;
19211986 const child_type = self.optionalChild(&buf);
......@@ -2400,6 +2465,7 @@ pub const Type = extern union {
24002465 .error_union,
24012466 .error_set,
24022467 .error_set_single,
2468 .error_set_inferred,
24032469 .@"opaque",
24042470 .var_args_param,
24052471 .manyptr_u8,
......@@ -2892,6 +2958,8 @@ pub const Type = extern union {
28922958 anyframe_T,
28932959 error_set,
28942960 error_set_single,
2961 /// The type is the inferred error set of a specific function.
2962 error_set_inferred,
28952963 empty_struct,
28962964 @"opaque",
28972965 @"struct",
......@@ -2989,6 +3057,7 @@ pub const Type = extern union {
29893057 => Payload.Bits,
29903058
29913059 .error_set => Payload.ErrorSet,
3060 .error_set_inferred => Payload.ErrorSetInferred,
29923061
29933062 .array, .vector => Payload.Array,
29943063 .array_sentinel => Payload.ArraySentinel,
......@@ -3081,6 +3150,13 @@ pub const Type = extern union {
30813150 data: *Module.ErrorSet,
30823151 };
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
30843160 pub const Pointer = struct {
30853161 pub const base_tag = Tag.pointer;
30863162
src/value.zig+22-5
......@@ -483,13 +483,13 @@ pub const Value = extern union {
483483 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
484484 /// we also need access to the type.
485485 pub fn format(
486 self: Value,
486 start_val: Value,
487487 comptime fmt: []const u8,
488488 options: std.fmt.FormatOptions,
489489 out_stream: anytype,
490490 ) !void {
491491 comptime assert(fmt.len == 0);
492 var val = self;
492 var val = start_val;
493493 while (true) switch (val.tag()) {
494494 .u8_type => return out_stream.writeAll("u8"),
495495 .i8_type => return out_stream.writeAll("i8"),
......@@ -598,9 +598,9 @@ pub const Value = extern union {
598598 val = field_ptr.container_ptr;
599599 },
600600 .empty_array => return out_stream.writeAll(".{}"),
601 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),
602 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),
603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.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})", .{val.castTag(.enum_field_index).?.data}),
603 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
604604 .repeated => {
605605 try out_stream.writeAll("(repeated) ");
606606 val = val.castTag(.repeated).?.data;
......@@ -1336,6 +1336,23 @@ pub const Value = extern union {
13361336 };
13371337 }
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
13391356 /// Asserts the value is a single-item pointer to an array, or an array,
13401357 /// or an unknown-length pointer, and returns the element value at the index.
13411358 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 {
804804 });
805805 }
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 );
820807 ctx.h("simple header", linux_x64,
821808 \\export fn start() void{}
822809 ,