| author | |
| committer | |
| log | 5a2620fcca55813d87000f3018e70509b1d325e0 |
| tree | ab2d91f93464da5cabcc844ccafde0d5eb2805cc |
| parent | c66481f9bcc5c08b92ccfd5d38d9d72be83479c0 |
4 files changed, 114 insertions(+), 50 deletions(-)
src/Module.zig+28-14| ... | ... | @@ -1223,14 +1223,20 @@ fn astgenAndSemaFn( |
| 1223 | 1223 | .{}, |
| 1224 | 1224 | ); |
| 1225 | 1225 | } |
| 1226 | if (fn_proto.ast.callconv_expr != 0) { | |
| 1227 | return mod.failNode( | |
| 1228 | &fn_type_scope.base, | |
| 1229 | fn_proto.ast.callconv_expr, | |
| 1230 | "TODO implement function calling convention expression", | |
| 1231 | .{}, | |
| 1232 | ); | |
| 1233 | } | |
| 1226 | const opt_cc: ?*zir.Inst = if (fn_proto.ast.callconv_expr != 0) cc: { | |
| 1227 | // TODO instead of enum literal type, this needs to be the | |
| 1228 | // std.builtin.CallingConvention enum. We need to implement importing other files | |
| 1229 | // and enums in order to fix this. | |
| 1230 | const src = token_starts[tree.firstToken(fn_proto.ast.callconv_expr)]; | |
| 1231 | const enum_lit_ty = try astgen.addZIRInstConst(mod, &fn_type_scope.base, src, .{ | |
| 1232 | .ty = Type.initTag(.type), | |
| 1233 | .val = Value.initTag(.enum_literal_type), | |
| 1234 | }); | |
| 1235 | break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{ | |
| 1236 | .ty = enum_lit_ty, | |
| 1237 | }, fn_proto.ast.callconv_expr); | |
| 1238 | } else null; | |
| 1239 | ||
| 1234 | 1240 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 1235 | 1241 | if (token_tags[maybe_bang] == .bang) { |
| 1236 | 1242 | return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{}); |
| ... | ... | @@ -1241,10 +1247,17 @@ fn astgenAndSemaFn( |
| 1241 | 1247 | type_type_rl, |
| 1242 | 1248 | fn_proto.ast.return_type, |
| 1243 | 1249 | ); |
| 1244 | const fn_type_inst = try astgen.addZIRInst(mod, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{ | |
| 1245 | .return_type = return_type_inst, | |
| 1246 | .param_types = param_types, | |
| 1247 | }, .{}); | |
| 1250 | const fn_type_inst = if (opt_cc) |cc| | |
| 1251 | try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{ | |
| 1252 | .return_type = return_type_inst, | |
| 1253 | .param_types = param_types, | |
| 1254 | .cc = cc, | |
| 1255 | }) | |
| 1256 | else | |
| 1257 | try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{ | |
| 1258 | .return_type = return_type_inst, | |
| 1259 | .param_types = param_types, | |
| 1260 | }); | |
| 1248 | 1261 | |
| 1249 | 1262 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { |
| 1250 | 1263 | zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {}; |
| ... | ... | @@ -1316,6 +1329,7 @@ fn astgenAndSemaFn( |
| 1316 | 1329 | .decl = decl, |
| 1317 | 1330 | .arena = &decl_arena.allocator, |
| 1318 | 1331 | .parent = &decl.container.base, |
| 1332 | .force_comptime = false, | |
| 1319 | 1333 | }; |
| 1320 | 1334 | defer gen_scope.instructions.deinit(mod.gpa); |
| 1321 | 1335 | |
| ... | ... | @@ -1348,7 +1362,7 @@ fn astgenAndSemaFn( |
| 1348 | 1362 | params_scope = &sub_scope.base; |
| 1349 | 1363 | } |
| 1350 | 1364 | |
| 1351 | try astgen.blockExpr(mod, params_scope, body_node); | |
| 1365 | try astgen.expr(mod, params_scope, .none, body_node); | |
| 1352 | 1366 | |
| 1353 | 1367 | if (gen_scope.instructions.items.len == 0 or |
| 1354 | 1368 | !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) |
| ... | ... | @@ -1496,7 +1510,7 @@ fn astgenAndSemaVarDecl( |
| 1496 | 1510 | assert(is_extern); |
| 1497 | 1511 | return mod.failTok(&block_scope.base, lib_name, "TODO implement function library name", .{}); |
| 1498 | 1512 | } |
| 1499 | const is_mutable = token_tags[var_decl.mut_token] == .keyword_var; | |
| 1513 | const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; | |
| 1500 | 1514 | const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: { |
| 1501 | 1515 | if (!is_mutable) { |
| 1502 | 1516 | return mod.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); |
src/astgen.zig+16-17| ... | ... | @@ -539,17 +539,6 @@ pub fn comptimeExpr( |
| 539 | 539 | } |
| 540 | 540 | |
| 541 | 541 | const tree = parent_scope.tree(); |
| 542 | const main_tokens = tree.nodes.items(.main_token); | |
| 543 | const token_tags = tree.tokens.items(.tag); | |
| 544 | ||
| 545 | // Optimization for labeled blocks: don't need to have 2 layers of blocks, | |
| 546 | // we can reuse the existing one. | |
| 547 | const lbrace = main_tokens[node]; | |
| 548 | if (token_tags[lbrace - 1] == .colon and | |
| 549 | token_tags[lbrace - 2] == .identifier) | |
| 550 | { | |
| 551 | return labeledBlockExpr(mod, parent_scope, rl, node, .block_comptime); | |
| 552 | } | |
| 553 | 542 | |
| 554 | 543 | // Make a scope to collect generated instructions in the sub-expression. |
| 555 | 544 | var block_scope: Scope.GenZIR = .{ |
| ... | ... | @@ -708,9 +697,13 @@ pub fn blockExpr( |
| 708 | 697 | const tracy = trace(@src()); |
| 709 | 698 | defer tracy.end(); |
| 710 | 699 | |
| 700 | const tree = scope.tree(); | |
| 701 | const main_tokens = tree.nodes.items(.main_token); | |
| 702 | const token_tags = tree.tokens.items(.tag); | |
| 703 | ||
| 711 | 704 | const lbrace = main_tokens[node]; |
| 712 | 705 | if (token_tags[lbrace - 1] == .colon) { |
| 713 | return labeledBlockExpr(mod, scope, rl, block_node, .block); | |
| 706 | return labeledBlockExpr(mod, scope, rl, block_node, statements, .block); | |
| 714 | 707 | } |
| 715 | 708 | |
| 716 | 709 | try blockExprStmts(mod, scope, block_node, statements); |
| ... | ... | @@ -766,7 +759,8 @@ fn labeledBlockExpr( |
| 766 | 759 | mod: *Module, |
| 767 | 760 | parent_scope: *Scope, |
| 768 | 761 | rl: ResultLoc, |
| 769 | block_node: *ast.Node.labeled_block, | |
| 762 | block_node: ast.Node.Index, | |
| 763 | statements: []const ast.Node.Index, | |
| 770 | 764 | zir_tag: zir.Inst.Tag, |
| 771 | 765 | ) InnerError!*zir.Inst { |
| 772 | 766 | const tracy = trace(@src()); |
| ... | ... | @@ -777,9 +771,14 @@ fn labeledBlockExpr( |
| 777 | 771 | const tree = parent_scope.tree(); |
| 778 | 772 | const node_datas = tree.nodes.items(.data); |
| 779 | 773 | const main_tokens = tree.nodes.items(.main_token); |
| 780 | const src = token_starts[block_node.lbrace]; | |
| 774 | const token_starts = tree.tokens.items(.start); | |
| 775 | ||
| 776 | const lbrace = main_tokens[block_node]; | |
| 777 | const label_token = lbrace - 1; | |
| 778 | assert(token_tags[label_token] == .identifier); | |
| 779 | const src = token_starts[lbrace]; | |
| 781 | 780 | |
| 782 | try checkLabelRedefinition(mod, parent_scope, block_node.label); | |
| 781 | try checkLabelRedefinition(mod, parent_scope, label_token); | |
| 783 | 782 | |
| 784 | 783 | // Create the Block ZIR instruction so that we can put it into the GenZIR struct |
| 785 | 784 | // so that break statements can reference it. |
| ... | ... | @@ -804,7 +803,7 @@ fn labeledBlockExpr( |
| 804 | 803 | .instructions = .{}, |
| 805 | 804 | // TODO @as here is working around a stage1 miscompilation bug :( |
| 806 | 805 | .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ |
| 807 | .token = block_node.label, | |
| 806 | .token = label_token, | |
| 808 | 807 | .block_inst = block_inst, |
| 809 | 808 | }), |
| 810 | 809 | }; |
| ... | ... | @@ -813,7 +812,7 @@ fn labeledBlockExpr( |
| 813 | 812 | defer block_scope.labeled_breaks.deinit(mod.gpa); |
| 814 | 813 | defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); |
| 815 | 814 | |
| 816 | try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); | |
| 815 | try blockExprStmts(mod, &block_scope.base, block_node, block_node.statements()); | |
| 817 | 816 | |
| 818 | 817 | if (!block_scope.label.?.used) { |
| 819 | 818 | return mod.fail(parent_scope, token_starts[block_node.label], "unused block label", .{}); |
src/zir.zig+20-5| ... | ... | @@ -172,8 +172,10 @@ pub const Inst = struct { |
| 172 | 172 | floatcast, |
| 173 | 173 | /// Declare a function body. |
| 174 | 174 | @"fn", |
| 175 | /// Returns a function type. | |
| 176 | fntype, | |
| 175 | /// Returns a function type, assuming unspecified calling convention. | |
| 176 | fn_type, | |
| 177 | /// Returns a function type, with a calling convention instruction operand. | |
| 178 | fn_type_cc, | |
| 177 | 179 | /// @import(operand) |
| 178 | 180 | import, |
| 179 | 181 | /// Integer literal. |
| ... | ... | @@ -478,7 +480,8 @@ pub const Inst = struct { |
| 478 | 480 | .@"export" => Export, |
| 479 | 481 | .param_type => ParamType, |
| 480 | 482 | .primitive => Primitive, |
| 481 | .fntype => FnType, | |
| 483 | .fn_type => FnType, | |
| 484 | .fn_type_cc => FnTypeCc, | |
| 482 | 485 | .elem_ptr, .elem_val => Elem, |
| 483 | 486 | .condbr => CondBr, |
| 484 | 487 | .ptr_type => PtrType, |
| ... | ... | @@ -552,7 +555,8 @@ pub const Inst = struct { |
| 552 | 555 | .field_ptr_named, |
| 553 | 556 | .field_val_named, |
| 554 | 557 | .@"fn", |
| 555 | .fntype, | |
| 558 | .fn_type, | |
| 559 | .fn_type_cc, | |
| 556 | 560 | .int, |
| 557 | 561 | .intcast, |
| 558 | 562 | .int_type, |
| ... | ... | @@ -877,7 +881,18 @@ pub const Inst = struct { |
| 877 | 881 | }; |
| 878 | 882 | |
| 879 | 883 | pub const FnType = struct { |
| 880 | pub const base_tag = Tag.fntype; | |
| 884 | pub const base_tag = Tag.fn_type; | |
| 885 | base: Inst, | |
| 886 | ||
| 887 | positionals: struct { | |
| 888 | param_types: []*Inst, | |
| 889 | return_type: *Inst, | |
| 890 | }, | |
| 891 | kw_args: struct {}, | |
| 892 | }; | |
| 893 | ||
| 894 | pub const FnTypeCc = struct { | |
| 895 | pub const base_tag = Tag.fn_type_cc; | |
| 881 | 896 | base: Inst, |
| 882 | 897 | |
| 883 | 898 | positionals: struct { |
src/zir_sema.zig+50-14| ... | ... | @@ -91,7 +91,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 91 | 91 | .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?), |
| 92 | 92 | .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?), |
| 93 | 93 | .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?), |
| 94 | .fntype => return zirFnType(mod, scope, old_inst.castTag(.fntype).?), | |
| 94 | .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?), | |
| 95 | .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?), | |
| 95 | 96 | .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?), |
| 96 | 97 | .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?), |
| 97 | 98 | .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?), |
| ... | ... | @@ -155,7 +156,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 155 | 156 | .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?), |
| 156 | 157 | .void_value => return mod.constVoid(scope, old_inst.src), |
| 157 | 158 | .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false), |
| 158 | .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, true), | |
| 159 | .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true), | |
| 159 | 160 | .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), |
| 160 | 161 | |
| 161 | 162 | .container_field_named, |
| ... | ... | @@ -958,11 +959,11 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 958 | 959 | ); |
| 959 | 960 | } |
| 960 | 961 | |
| 961 | if (inst.kw_args.modifier == .compile_time) { | |
| 962 | if (inst.positionals.modifier == .compile_time) { | |
| 962 | 963 | return mod.fail(scope, inst.base.src, "TODO implement comptime function calls", .{}); |
| 963 | 964 | } |
| 964 | if (inst.kw_args.modifier != .auto) { | |
| 965 | return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.kw_args.modifier}); | |
| 965 | if (inst.positionals.modifier != .auto) { | |
| 966 | return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.positionals.modifier}); | |
| 966 | 967 | } |
| 967 | 968 | |
| 968 | 969 | // TODO handle function calls of generic functions |
| ... | ... | @@ -1295,34 +1296,69 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) |
| 1295 | 1296 | fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| 1296 | 1297 | const tracy = trace(@src()); |
| 1297 | 1298 | defer tracy.end(); |
| 1298 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); | |
| 1299 | ||
| 1300 | return fnTypeCommon( | |
| 1301 | mod, | |
| 1302 | scope, | |
| 1303 | &fntype.base, | |
| 1304 | fntype.positionals.param_types, | |
| 1305 | fntype.positionals.return_type, | |
| 1306 | .Unspecified, | |
| 1307 | ); | |
| 1308 | } | |
| 1309 | ||
| 1310 | fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerError!*Inst { | |
| 1311 | const tracy = trace(@src()); | |
| 1312 | defer tracy.end(); | |
| 1313 | ||
| 1299 | 1314 | const cc_tv = try resolveInstConst(mod, scope, fntype.positionals.cc); |
| 1315 | // TODO once we're capable of importing and analyzing decls from | |
| 1316 | // std.builtin, this needs to change | |
| 1300 | 1317 | const cc_str = cc_tv.val.castTag(.enum_literal).?.data; |
| 1301 | 1318 | const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse |
| 1302 | 1319 | return mod.fail(scope, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str}); |
| 1320 | return fnTypeCommon( | |
| 1321 | mod, | |
| 1322 | scope, | |
| 1323 | &fntype.base, | |
| 1324 | fntype.positionals.param_types, | |
| 1325 | fntype.positionals.return_type, | |
| 1326 | cc, | |
| 1327 | ); | |
| 1328 | } | |
| 1329 | ||
| 1330 | fn fnTypeCommon( | |
| 1331 | mod: *Module, | |
| 1332 | scope: *Scope, | |
| 1333 | zir_inst: *zir.Inst, | |
| 1334 | zir_param_types: []*zir.Inst, | |
| 1335 | zir_return_type: *zir.Inst, | |
| 1336 | cc: std.builtin.CallingConvention, | |
| 1337 | ) InnerError!*Inst { | |
| 1338 | const return_type = try resolveType(mod, scope, zir_return_type); | |
| 1303 | 1339 | |
| 1304 | 1340 | // Hot path for some common function types. |
| 1305 | if (fntype.positionals.param_types.len == 0) { | |
| 1341 | if (zir_param_types.len == 0) { | |
| 1306 | 1342 | if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { |
| 1307 | return mod.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args)); | |
| 1343 | return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args)); | |
| 1308 | 1344 | } |
| 1309 | 1345 | |
| 1310 | 1346 | if (return_type.zigTypeTag() == .Void and cc == .Unspecified) { |
| 1311 | return mod.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args)); | |
| 1347 | return mod.constType(scope, zir_inst.src, Type.initTag(.fn_void_no_args)); | |
| 1312 | 1348 | } |
| 1313 | 1349 | |
| 1314 | 1350 | if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) { |
| 1315 | return mod.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); | |
| 1351 | return mod.constType(scope, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args)); | |
| 1316 | 1352 | } |
| 1317 | 1353 | |
| 1318 | 1354 | if (return_type.zigTypeTag() == .Void and cc == .C) { |
| 1319 | return mod.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); | |
| 1355 | return mod.constType(scope, zir_inst.src, Type.initTag(.fn_ccc_void_no_args)); | |
| 1320 | 1356 | } |
| 1321 | 1357 | } |
| 1322 | 1358 | |
| 1323 | 1359 | const arena = scope.arena(); |
| 1324 | const param_types = try arena.alloc(Type, fntype.positionals.param_types.len); | |
| 1325 | for (fntype.positionals.param_types) |param_type, i| { | |
| 1360 | const param_types = try arena.alloc(Type, zir_param_types.len); | |
| 1361 | for (zir_param_types) |param_type, i| { | |
| 1326 | 1362 | const resolved = try resolveType(mod, scope, param_type); |
| 1327 | 1363 | // TODO skip for comptime params |
| 1328 | 1364 | if (!resolved.isValidVarType(false)) { |
| ... | ... | @@ -1336,7 +1372,7 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!* |
| 1336 | 1372 | .return_type = return_type, |
| 1337 | 1373 | .cc = cc, |
| 1338 | 1374 | }); |
| 1339 | return mod.constType(scope, fntype.base.src, fn_ty); | |
| 1375 | return mod.constType(scope, zir_inst.src, fn_ty); | |
| 1340 | 1376 | } |
| 1341 | 1377 | |
| 1342 | 1378 | fn zirPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst { |