From 5a2620fcca55813d87000f3018e70509b1d325e0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 17 Feb 2021 22:22:10 -0700 Subject: [PATCH] stage2: fix some of the compilation errors in this branch --- src/Module.zig | 42 ++++++++++++++++++++----------- src/astgen.zig | 33 ++++++++++++------------- src/zir.zig | 25 +++++++++++++++---- src/zir_sema.zig | 64 +++++++++++++++++++++++++++++++++++++----------- 4 files changed, 114 insertions(+), 50 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 19566dee43..17084677d4 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1223,14 +1223,20 @@ fn astgenAndSemaFn( .{}, ); } - if (fn_proto.ast.callconv_expr != 0) { - return mod.failNode( - &fn_type_scope.base, - fn_proto.ast.callconv_expr, - "TODO implement function calling convention expression", - .{}, - ); - } + const opt_cc: ?*zir.Inst = if (fn_proto.ast.callconv_expr != 0) cc: { + // TODO instead of enum literal type, this needs to be the + // std.builtin.CallingConvention enum. We need to implement importing other files + // and enums in order to fix this. + const src = token_starts[tree.firstToken(fn_proto.ast.callconv_expr)]; + const enum_lit_ty = try astgen.addZIRInstConst(mod, &fn_type_scope.base, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.enum_literal_type), + }); + break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{ + .ty = enum_lit_ty, + }, fn_proto.ast.callconv_expr); + } else null; + const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; if (token_tags[maybe_bang] == .bang) { return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{}); @@ -1241,10 +1247,17 @@ fn astgenAndSemaFn( type_type_rl, fn_proto.ast.return_type, ); - const fn_type_inst = try astgen.addZIRInst(mod, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{ - .return_type = return_type_inst, - .param_types = param_types, - }, .{}); + const fn_type_inst = if (opt_cc) |cc| + try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{ + .return_type = return_type_inst, + .param_types = param_types, + .cc = cc, + }) + else + try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{ + .return_type = return_type_inst, + .param_types = param_types, + }); if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {}; @@ -1316,6 +1329,7 @@ fn astgenAndSemaFn( .decl = decl, .arena = &decl_arena.allocator, .parent = &decl.container.base, + .force_comptime = false, }; defer gen_scope.instructions.deinit(mod.gpa); @@ -1348,7 +1362,7 @@ fn astgenAndSemaFn( params_scope = &sub_scope.base; } - try astgen.blockExpr(mod, params_scope, body_node); + try astgen.expr(mod, params_scope, .none, body_node); if (gen_scope.instructions.items.len == 0 or !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) @@ -1496,7 +1510,7 @@ fn astgenAndSemaVarDecl( assert(is_extern); return mod.failTok(&block_scope.base, lib_name, "TODO implement function library name", .{}); } - const is_mutable = token_tags[var_decl.mut_token] == .keyword_var; + const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: { if (!is_mutable) { return mod.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); diff --git a/src/astgen.zig b/src/astgen.zig index aef1b21a6c..125e9bceda 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -539,17 +539,6 @@ pub fn comptimeExpr( } const tree = parent_scope.tree(); - const main_tokens = tree.nodes.items(.main_token); - const token_tags = tree.tokens.items(.tag); - - // Optimization for labeled blocks: don't need to have 2 layers of blocks, - // we can reuse the existing one. - const lbrace = main_tokens[node]; - if (token_tags[lbrace - 1] == .colon and - token_tags[lbrace - 2] == .identifier) - { - return labeledBlockExpr(mod, parent_scope, rl, node, .block_comptime); - } // Make a scope to collect generated instructions in the sub-expression. var block_scope: Scope.GenZIR = .{ @@ -708,9 +697,13 @@ pub fn blockExpr( const tracy = trace(@src()); defer tracy.end(); + const tree = scope.tree(); + const main_tokens = tree.nodes.items(.main_token); + const token_tags = tree.tokens.items(.tag); + const lbrace = main_tokens[node]; if (token_tags[lbrace - 1] == .colon) { - return labeledBlockExpr(mod, scope, rl, block_node, .block); + return labeledBlockExpr(mod, scope, rl, block_node, statements, .block); } try blockExprStmts(mod, scope, block_node, statements); @@ -766,7 +759,8 @@ fn labeledBlockExpr( mod: *Module, parent_scope: *Scope, rl: ResultLoc, - block_node: *ast.Node.labeled_block, + block_node: ast.Node.Index, + statements: []const ast.Node.Index, zir_tag: zir.Inst.Tag, ) InnerError!*zir.Inst { const tracy = trace(@src()); @@ -777,9 +771,14 @@ fn labeledBlockExpr( const tree = parent_scope.tree(); const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); - const src = token_starts[block_node.lbrace]; + const token_starts = tree.tokens.items(.start); - try checkLabelRedefinition(mod, parent_scope, block_node.label); + const lbrace = main_tokens[block_node]; + const label_token = lbrace - 1; + assert(token_tags[label_token] == .identifier); + const src = token_starts[lbrace]; + + try checkLabelRedefinition(mod, parent_scope, label_token); // Create the Block ZIR instruction so that we can put it into the GenZIR struct // so that break statements can reference it. @@ -804,7 +803,7 @@ fn labeledBlockExpr( .instructions = .{}, // TODO @as here is working around a stage1 miscompilation bug :( .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{ - .token = block_node.label, + .token = label_token, .block_inst = block_inst, }), }; @@ -813,7 +812,7 @@ fn labeledBlockExpr( defer block_scope.labeled_breaks.deinit(mod.gpa); defer block_scope.labeled_store_to_block_ptr_list.deinit(mod.gpa); - try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements()); + try blockExprStmts(mod, &block_scope.base, block_node, block_node.statements()); if (!block_scope.label.?.used) { return mod.fail(parent_scope, token_starts[block_node.label], "unused block label", .{}); diff --git a/src/zir.zig b/src/zir.zig index fcbcee9ccd..9a3c080760 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -172,8 +172,10 @@ pub const Inst = struct { floatcast, /// Declare a function body. @"fn", - /// Returns a function type. - fntype, + /// Returns a function type, assuming unspecified calling convention. + fn_type, + /// Returns a function type, with a calling convention instruction operand. + fn_type_cc, /// @import(operand) import, /// Integer literal. @@ -478,7 +480,8 @@ pub const Inst = struct { .@"export" => Export, .param_type => ParamType, .primitive => Primitive, - .fntype => FnType, + .fn_type => FnType, + .fn_type_cc => FnTypeCc, .elem_ptr, .elem_val => Elem, .condbr => CondBr, .ptr_type => PtrType, @@ -552,7 +555,8 @@ pub const Inst = struct { .field_ptr_named, .field_val_named, .@"fn", - .fntype, + .fn_type, + .fn_type_cc, .int, .intcast, .int_type, @@ -877,7 +881,18 @@ pub const Inst = struct { }; pub const FnType = struct { - pub const base_tag = Tag.fntype; + pub const base_tag = Tag.fn_type; + base: Inst, + + positionals: struct { + param_types: []*Inst, + return_type: *Inst, + }, + kw_args: struct {}, + }; + + pub const FnTypeCc = struct { + pub const base_tag = Tag.fn_type_cc; base: Inst, positionals: struct { diff --git a/src/zir_sema.zig b/src/zir_sema.zig index 80146397c5..1a2e99ded5 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -91,7 +91,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?), .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?), .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?), - .fntype => return zirFnType(mod, scope, old_inst.castTag(.fntype).?), + .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?), + .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?), .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?), .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?), .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! .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?), .void_value => return mod.constVoid(scope, old_inst.src), .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false), - .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, true), + .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true), .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), .container_field_named, @@ -958,11 +959,11 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { ); } - if (inst.kw_args.modifier == .compile_time) { + if (inst.positionals.modifier == .compile_time) { return mod.fail(scope, inst.base.src, "TODO implement comptime function calls", .{}); } - if (inst.kw_args.modifier != .auto) { - return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.kw_args.modifier}); + if (inst.positionals.modifier != .auto) { + return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.positionals.modifier}); } // TODO handle function calls of generic functions @@ -1295,34 +1296,69 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { const tracy = trace(@src()); defer tracy.end(); - const return_type = try resolveType(mod, scope, fntype.positionals.return_type); + + return fnTypeCommon( + mod, + scope, + &fntype.base, + fntype.positionals.param_types, + fntype.positionals.return_type, + .Unspecified, + ); +} + +fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerError!*Inst { + const tracy = trace(@src()); + defer tracy.end(); + const cc_tv = try resolveInstConst(mod, scope, fntype.positionals.cc); + // TODO once we're capable of importing and analyzing decls from + // std.builtin, this needs to change const cc_str = cc_tv.val.castTag(.enum_literal).?.data; const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse return mod.fail(scope, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str}); + return fnTypeCommon( + mod, + scope, + &fntype.base, + fntype.positionals.param_types, + fntype.positionals.return_type, + cc, + ); +} + +fn fnTypeCommon( + mod: *Module, + scope: *Scope, + zir_inst: *zir.Inst, + zir_param_types: []*zir.Inst, + zir_return_type: *zir.Inst, + cc: std.builtin.CallingConvention, +) InnerError!*Inst { + const return_type = try resolveType(mod, scope, zir_return_type); // Hot path for some common function types. - if (fntype.positionals.param_types.len == 0) { + if (zir_param_types.len == 0) { if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { - return mod.constType(scope, fntype.base.src, Type.initTag(.fn_noreturn_no_args)); + return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args)); } if (return_type.zigTypeTag() == .Void and cc == .Unspecified) { - return mod.constType(scope, fntype.base.src, Type.initTag(.fn_void_no_args)); + return mod.constType(scope, zir_inst.src, Type.initTag(.fn_void_no_args)); } if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) { - return mod.constType(scope, fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); + return mod.constType(scope, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args)); } if (return_type.zigTypeTag() == .Void and cc == .C) { - return mod.constType(scope, fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); + return mod.constType(scope, zir_inst.src, Type.initTag(.fn_ccc_void_no_args)); } } const arena = scope.arena(); - const param_types = try arena.alloc(Type, fntype.positionals.param_types.len); - for (fntype.positionals.param_types) |param_type, i| { + const param_types = try arena.alloc(Type, zir_param_types.len); + for (zir_param_types) |param_type, i| { const resolved = try resolveType(mod, scope, param_type); // TODO skip for comptime params if (!resolved.isValidVarType(false)) { @@ -1336,7 +1372,7 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!* .return_type = return_type, .cc = cc, }); - return mod.constType(scope, fntype.base.src, fn_ty); + return mod.constType(scope, zir_inst.src, fn_ty); } fn zirPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {