| author | |
| committer | |
| log | b2deaf80279aab1322036e55a9646ecbaaa47f44 |
| tree | f950b7d882299bab45a6d5ea8cd213d1850c2bb0 |
| parent | 4bfcd105eff797aceb621d2c8b971c15fef6e450 |
* zir.Code: introduce a decls array. This is so that `decl_val` and
`decl_ref` instructions can refer to a Decl with a u32 and therefore
they can also store a source location. This is needed for proper
compile error reporting.
* astgen uses a hash map to avoid redundantly adding a Decl to the
decls array.
* fixed reporting "instruction illegal outside function body" instead
of the desired message "unable to resolve comptime value".
* astgen skips emitting dbg_stmt instructions in comptime scopes.
* astgen has some logic to avoid adding unnecessary type coercion
instructions for common values.6 files changed, 148 insertions(+), 66 deletions(-)
BRANCH_TODO+3| ... | ... | @@ -38,3 +38,6 @@ Performance optimizations to look into: |
| 38 | 38 | * astgen for loops using pointer arithmetic because it's faster and if the programmer |
| 39 | 39 | wants an index capture, that will just be a convenience variable that zig sets up |
| 40 | 40 | independently. |
| 41 | * in astgen, if a decl_val would be to a const variable or to a function, there could be | |
| 42 | a special zir.Inst.Ref form that means to refer to a decl as the operand. This | |
| 43 | would elide all the decl_val instructions in the ZIR. |
src/Module.zig+21-12| ... | ... | @@ -103,7 +103,7 @@ stage1_flags: packed struct { |
| 103 | 103 | |
| 104 | 104 | emit_h: ?Compilation.EmitLoc, |
| 105 | 105 | |
| 106 | compile_log_text: std.ArrayListUnmanaged(u8) = .{}, | |
| 106 | compile_log_text: ArrayListUnmanaged(u8) = .{}, | |
| 107 | 107 | |
| 108 | 108 | pub const Export = struct { |
| 109 | 109 | options: std.builtin.ExportOptions, |
| ... | ... | @@ -335,7 +335,7 @@ pub const Decl = struct { |
| 335 | 335 | |
| 336 | 336 | /// This state is attached to every Decl when Module emit_h is non-null. |
| 337 | 337 | pub const EmitH = struct { |
| 338 | fwd_decl: std.ArrayListUnmanaged(u8) = .{}, | |
| 338 | fwd_decl: ArrayListUnmanaged(u8) = .{}, | |
| 339 | 339 | }; |
| 340 | 340 | |
| 341 | 341 | /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. |
| ... | ... | @@ -916,7 +916,7 @@ pub const Scope = struct { |
| 916 | 916 | zir_code: *WipZirCode, |
| 917 | 917 | /// Keeps track of the list of instructions in this scope only. Indexes |
| 918 | 918 | /// to instructions in `zir_code`. |
| 919 | instructions: std.ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 919 | instructions: ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 920 | 920 | label: ?Label = null, |
| 921 | 921 | break_block: zir.Inst.Index = 0, |
| 922 | 922 | continue_block: zir.Inst.Index = 0, |
| ... | ... | @@ -935,11 +935,11 @@ pub const Scope = struct { |
| 935 | 935 | break_count: usize = 0, |
| 936 | 936 | /// Tracks `break :foo bar` instructions so they can possibly be elided later if |
| 937 | 937 | /// the labeled block ends up not needing a result location pointer. |
| 938 | labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 938 | labeled_breaks: ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 939 | 939 | /// Tracks `store_to_block_ptr` instructions that correspond to break instructions |
| 940 | 940 | /// so they can possibly be elided later if the labeled block ends up not needing |
| 941 | 941 | /// a result location pointer. |
| 942 | labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 942 | labeled_store_to_block_ptr_list: ArrayListUnmanaged(zir.Inst.Index) = .{}, | |
| 943 | 943 | |
| 944 | 944 | pub const Label = struct { |
| 945 | 945 | token: ast.TokenIndex, |
| ... | ... | @@ -957,6 +957,7 @@ pub const Scope = struct { |
| 957 | 957 | .instructions = gz.zir_code.instructions.toOwnedSlice(), |
| 958 | 958 | .string_bytes = gz.zir_code.string_bytes.toOwnedSlice(gpa), |
| 959 | 959 | .extra = gz.zir_code.extra.toOwnedSlice(gpa), |
| 960 | .decls = gz.zir_code.decls.toOwnedSlice(gpa), | |
| 960 | 961 | }; |
| 961 | 962 | } |
| 962 | 963 | |
| ... | ... | @@ -1253,11 +1254,15 @@ pub const Scope = struct { |
| 1253 | 1254 | pub fn addDecl( |
| 1254 | 1255 | gz: *GenZir, |
| 1255 | 1256 | tag: zir.Inst.Tag, |
| 1256 | decl: *Decl, | |
| 1257 | decl_index: u32, | |
| 1258 | src_node: ast.Node.Index, | |
| 1257 | 1259 | ) !zir.Inst.Ref { |
| 1258 | 1260 | return gz.add(.{ |
| 1259 | 1261 | .tag = tag, |
| 1260 | .data = .{ .decl = decl }, | |
| 1262 | .data = .{ .pl_node = .{ | |
| 1263 | .src_node = gz.zir_code.decl.nodeIndexToRelative(src_node), | |
| 1264 | .payload_index = decl_index, | |
| 1265 | } }, | |
| 1261 | 1266 | }); |
| 1262 | 1267 | } |
| 1263 | 1268 | |
| ... | ... | @@ -1379,8 +1384,10 @@ pub const Scope = struct { |
| 1379 | 1384 | /// The `GenZir.finish` function converts this to a `zir.Code`. |
| 1380 | 1385 | pub const WipZirCode = struct { |
| 1381 | 1386 | instructions: std.MultiArrayList(zir.Inst) = .{}, |
| 1382 | string_bytes: std.ArrayListUnmanaged(u8) = .{}, | |
| 1383 | extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 1387 | string_bytes: ArrayListUnmanaged(u8) = .{}, | |
| 1388 | extra: ArrayListUnmanaged(u32) = .{}, | |
| 1389 | decl_map: std.StringArrayHashMapUnmanaged(void) = .{}, | |
| 1390 | decls: ArrayListUnmanaged(*Decl) = .{}, | |
| 1384 | 1391 | /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert |
| 1385 | 1392 | /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters. |
| 1386 | 1393 | ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len, |
| ... | ... | @@ -1442,6 +1449,8 @@ pub const WipZirCode = struct { |
| 1442 | 1449 | wzc.instructions.deinit(wzc.gpa); |
| 1443 | 1450 | wzc.extra.deinit(wzc.gpa); |
| 1444 | 1451 | wzc.string_bytes.deinit(wzc.gpa); |
| 1452 | wzc.decl_map.deinit(wzc.gpa); | |
| 1453 | wzc.decls.deinit(wzc.gpa); | |
| 1445 | 1454 | } |
| 1446 | 1455 | }; |
| 1447 | 1456 | |
| ... | ... | @@ -4062,7 +4071,7 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) |
| 4062 | 4071 | if (!mem.startsWith(u8, ident_name, "@")) { |
| 4063 | 4072 | return ident_name; |
| 4064 | 4073 | } |
| 4065 | var buf: std.ArrayListUnmanaged(u8) = .{}; | |
| 4074 | var buf: ArrayListUnmanaged(u8) = .{}; | |
| 4066 | 4075 | defer buf.deinit(mod.gpa); |
| 4067 | 4076 | try parseStrLit(mod, scope, token, &buf, ident_name, 1); |
| 4068 | 4077 | return buf.toOwnedSlice(mod.gpa); |
| ... | ... | @@ -4075,7 +4084,7 @@ pub fn appendIdentStr( |
| 4075 | 4084 | mod: *Module, |
| 4076 | 4085 | scope: *Scope, |
| 4077 | 4086 | token: ast.TokenIndex, |
| 4078 | buf: *std.ArrayListUnmanaged(u8), | |
| 4087 | buf: *ArrayListUnmanaged(u8), | |
| 4079 | 4088 | ) InnerError!void { |
| 4080 | 4089 | const tree = scope.tree(); |
| 4081 | 4090 | const token_tags = tree.tokens.items(.tag); |
| ... | ... | @@ -4093,7 +4102,7 @@ pub fn parseStrLit( |
| 4093 | 4102 | mod: *Module, |
| 4094 | 4103 | scope: *Scope, |
| 4095 | 4104 | token: ast.TokenIndex, |
| 4096 | buf: *std.ArrayListUnmanaged(u8), | |
| 4105 | buf: *ArrayListUnmanaged(u8), | |
| 4097 | 4106 | bytes: []const u8, |
| 4098 | 4107 | offset: u32, |
| 4099 | 4108 | ) InnerError!void { |
src/Sema.zig+14-5| ... | ... | @@ -1102,10 +1102,15 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE |
| 1102 | 1102 | const tracy = trace(@src()); |
| 1103 | 1103 | defer tracy.end(); |
| 1104 | 1104 | |
| 1105 | // We do not set sema.src here because dbg_stmt instructions are only emitted for | |
| 1106 | // ZIR code that possibly will need to generate runtime code. So error messages | |
| 1107 | // and other source locations must not rely on sema.src being set from dbg_stmt | |
| 1108 | // instructions. | |
| 1105 | 1109 | if (block.is_comptime) return; |
| 1106 | 1110 | |
| 1107 | 1111 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 1108 | 1112 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 1113 | ||
| 1109 | 1114 | const src_loc = src.toSrcLoc(&block.base); |
| 1110 | 1115 | const abs_byte_off = try src_loc.byteOffset(); |
| 1111 | 1116 | _ = try block.addDbgStmt(src, abs_byte_off); |
| ... | ... | @@ -1115,16 +1120,20 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError |
| 1115 | 1120 | const tracy = trace(@src()); |
| 1116 | 1121 | defer tracy.end(); |
| 1117 | 1122 | |
| 1118 | const decl = sema.code.instructions.items(.data)[inst].decl; | |
| 1119 | return sema.analyzeDeclRef(block, .unneeded, decl); | |
| 1123 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 1124 | const src = inst_data.src(); | |
| 1125 | const decl = sema.code.decls[inst_data.payload_index]; | |
| 1126 | return sema.analyzeDeclRef(block, src, decl); | |
| 1120 | 1127 | } |
| 1121 | 1128 | |
| 1122 | 1129 | fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst { |
| 1123 | 1130 | const tracy = trace(@src()); |
| 1124 | 1131 | defer tracy.end(); |
| 1125 | 1132 | |
| 1126 | const decl = sema.code.instructions.items(.data)[inst].decl; | |
| 1127 | return sema.analyzeDeclVal(block, .unneeded, decl); | |
| 1133 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | |
| 1134 | const src = inst_data.src(); | |
| 1135 | const decl = sema.code.decls[inst_data.payload_index]; | |
| 1136 | return sema.analyzeDeclVal(block, src, decl); | |
| 1128 | 1137 | } |
| 1129 | 1138 | |
| 1130 | 1139 | fn zirCallNone( |
| ... | ... | @@ -3211,10 +3220,10 @@ fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void |
| 3211 | 3220 | } |
| 3212 | 3221 | |
| 3213 | 3222 | fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void { |
| 3214 | try sema.requireFunctionBlock(block, src); | |
| 3215 | 3223 | if (block.is_comptime) { |
| 3216 | 3224 | return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{}); |
| 3217 | 3225 | } |
| 3226 | try sema.requireFunctionBlock(block, src); | |
| 3218 | 3227 | } |
| 3219 | 3228 | |
| 3220 | 3229 | fn validateVarType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void { |
src/astgen.zig+77-12| ... | ... | @@ -952,7 +952,9 @@ fn blockExprStmts( |
| 952 | 952 | |
| 953 | 953 | var scope = parent_scope; |
| 954 | 954 | for (statements) |statement| { |
| 955 | _ = try gz.addNode(.dbg_stmt_node, statement); | |
| 955 | if (!gz.force_comptime) { | |
| 956 | _ = try gz.addNode(.dbg_stmt_node, statement); | |
| 957 | } | |
| 956 | 958 | switch (node_tags[statement]) { |
| 957 | 959 | .global_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)), |
| 958 | 960 | .local_var_decl => scope = try varDecl(mod, scope, statement, &block_arena.allocator, tree.localVarDecl(statement)), |
| ... | ... | @@ -2846,14 +2848,17 @@ fn identifier( |
| 2846 | 2848 | }; |
| 2847 | 2849 | } |
| 2848 | 2850 | |
| 2849 | if (mod.lookupDeclName(scope, ident_name)) |decl| { | |
| 2850 | return if (rl == .ref) | |
| 2851 | gz.addDecl(.decl_ref, decl) | |
| 2852 | else | |
| 2853 | rvalue(mod, scope, rl, try gz.addDecl(.decl_val, decl), ident); | |
| 2851 | const gop = try gz.zir_code.decl_map.getOrPut(mod.gpa, ident_name); | |
| 2852 | if (!gop.found_existing) { | |
| 2853 | const decl = mod.lookupDeclName(scope, ident_name) orelse | |
| 2854 | return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name}); | |
| 2855 | try gz.zir_code.decls.append(mod.gpa, decl); | |
| 2856 | } | |
| 2857 | const decl_index = @intCast(u32, gop.index); | |
| 2858 | switch (rl) { | |
| 2859 | .ref => return gz.addDecl(.decl_ref, decl_index, ident), | |
| 2860 | else => return rvalue(mod, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident), | |
| 2854 | 2861 | } |
| 2855 | ||
| 2856 | return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name}); | |
| 2857 | 2862 | } |
| 2858 | 2863 | |
| 2859 | 2864 | fn stringLiteral( |
| ... | ... | @@ -3743,10 +3748,70 @@ fn rvalue( |
| 3743 | 3748 | const src_token = tree.firstToken(src_node); |
| 3744 | 3749 | return gz.addUnTok(.ref, result, src_token); |
| 3745 | 3750 | }, |
| 3746 | .ty => |ty_inst| return gz.addPlNode(.as_node, src_node, zir.Inst.As{ | |
| 3747 | .dest_type = ty_inst, | |
| 3748 | .operand = result, | |
| 3749 | }), | |
| 3751 | .ty => |ty_inst| { | |
| 3752 | // Quickly eliminate some common, unnecessary type coercion. | |
| 3753 | const as_ty = @as(u64, @enumToInt(zir.Inst.Ref.type_type)) << 32; | |
| 3754 | const as_comptime_int = @as(u64, @enumToInt(zir.Inst.Ref.comptime_int_type)) << 32; | |
| 3755 | const as_bool = @as(u64, @enumToInt(zir.Inst.Ref.bool_type)) << 32; | |
| 3756 | const as_usize = @as(u64, @enumToInt(zir.Inst.Ref.usize_type)) << 32; | |
| 3757 | const as_void = @as(u64, @enumToInt(zir.Inst.Ref.void_type)) << 32; | |
| 3758 | switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) { | |
| 3759 | as_ty | @enumToInt(zir.Inst.Ref.u8_type), | |
| 3760 | as_ty | @enumToInt(zir.Inst.Ref.i8_type), | |
| 3761 | as_ty | @enumToInt(zir.Inst.Ref.u16_type), | |
| 3762 | as_ty | @enumToInt(zir.Inst.Ref.i16_type), | |
| 3763 | as_ty | @enumToInt(zir.Inst.Ref.u32_type), | |
| 3764 | as_ty | @enumToInt(zir.Inst.Ref.i32_type), | |
| 3765 | as_ty | @enumToInt(zir.Inst.Ref.u64_type), | |
| 3766 | as_ty | @enumToInt(zir.Inst.Ref.i64_type), | |
| 3767 | as_ty | @enumToInt(zir.Inst.Ref.usize_type), | |
| 3768 | as_ty | @enumToInt(zir.Inst.Ref.isize_type), | |
| 3769 | as_ty | @enumToInt(zir.Inst.Ref.c_short_type), | |
| 3770 | as_ty | @enumToInt(zir.Inst.Ref.c_ushort_type), | |
| 3771 | as_ty | @enumToInt(zir.Inst.Ref.c_int_type), | |
| 3772 | as_ty | @enumToInt(zir.Inst.Ref.c_uint_type), | |
| 3773 | as_ty | @enumToInt(zir.Inst.Ref.c_long_type), | |
| 3774 | as_ty | @enumToInt(zir.Inst.Ref.c_ulong_type), | |
| 3775 | as_ty | @enumToInt(zir.Inst.Ref.c_longlong_type), | |
| 3776 | as_ty | @enumToInt(zir.Inst.Ref.c_ulonglong_type), | |
| 3777 | as_ty | @enumToInt(zir.Inst.Ref.c_longdouble_type), | |
| 3778 | as_ty | @enumToInt(zir.Inst.Ref.f16_type), | |
| 3779 | as_ty | @enumToInt(zir.Inst.Ref.f32_type), | |
| 3780 | as_ty | @enumToInt(zir.Inst.Ref.f64_type), | |
| 3781 | as_ty | @enumToInt(zir.Inst.Ref.f128_type), | |
| 3782 | as_ty | @enumToInt(zir.Inst.Ref.c_void_type), | |
| 3783 | as_ty | @enumToInt(zir.Inst.Ref.bool_type), | |
| 3784 | as_ty | @enumToInt(zir.Inst.Ref.void_type), | |
| 3785 | as_ty | @enumToInt(zir.Inst.Ref.type_type), | |
| 3786 | as_ty | @enumToInt(zir.Inst.Ref.anyerror_type), | |
| 3787 | as_ty | @enumToInt(zir.Inst.Ref.comptime_int_type), | |
| 3788 | as_ty | @enumToInt(zir.Inst.Ref.comptime_float_type), | |
| 3789 | as_ty | @enumToInt(zir.Inst.Ref.noreturn_type), | |
| 3790 | as_ty | @enumToInt(zir.Inst.Ref.null_type), | |
| 3791 | as_ty | @enumToInt(zir.Inst.Ref.undefined_type), | |
| 3792 | as_ty | @enumToInt(zir.Inst.Ref.fn_noreturn_no_args_type), | |
| 3793 | as_ty | @enumToInt(zir.Inst.Ref.fn_void_no_args_type), | |
| 3794 | as_ty | @enumToInt(zir.Inst.Ref.fn_naked_noreturn_no_args_type), | |
| 3795 | as_ty | @enumToInt(zir.Inst.Ref.fn_ccc_void_no_args_type), | |
| 3796 | as_ty | @enumToInt(zir.Inst.Ref.single_const_pointer_to_comptime_int_type), | |
| 3797 | as_ty | @enumToInt(zir.Inst.Ref.const_slice_u8_type), | |
| 3798 | as_ty | @enumToInt(zir.Inst.Ref.enum_literal_type), | |
| 3799 | as_comptime_int | @enumToInt(zir.Inst.Ref.zero), | |
| 3800 | as_comptime_int | @enumToInt(zir.Inst.Ref.one), | |
| 3801 | as_bool | @enumToInt(zir.Inst.Ref.bool_true), | |
| 3802 | as_bool | @enumToInt(zir.Inst.Ref.bool_false), | |
| 3803 | as_usize | @enumToInt(zir.Inst.Ref.zero_usize), | |
| 3804 | as_usize | @enumToInt(zir.Inst.Ref.one_usize), | |
| 3805 | as_void | @enumToInt(zir.Inst.Ref.void_value), | |
| 3806 | => return result, // type of result is already correct | |
| 3807 | ||
| 3808 | // Need an explicit type coercion instruction. | |
| 3809 | else => return gz.addPlNode(.as_node, src_node, zir.Inst.As{ | |
| 3810 | .dest_type = ty_inst, | |
| 3811 | .operand = result, | |
| 3812 | }), | |
| 3813 | } | |
| 3814 | }, | |
| 3750 | 3815 | .ptr => |ptr_inst| { |
| 3751 | 3816 | _ = try gz.addPlNode(.store_node, src_node, zir.Inst.Bin{ |
| 3752 | 3817 | .lhs = ptr_inst, |
src/zir.zig+18-22| ... | ... | @@ -37,6 +37,8 @@ pub const Code = struct { |
| 37 | 37 | string_bytes: []u8, |
| 38 | 38 | /// The meaning of this data is determined by `Inst.Tag` value. |
| 39 | 39 | extra: []u32, |
| 40 | /// Used for decl_val and decl_ref instructions. | |
| 41 | decls: []*Module.Decl, | |
| 40 | 42 | |
| 41 | 43 | /// Returns the requested data, as well as the new index which is at the start of the |
| 42 | 44 | /// trailers for the object. |
| ... | ... | @@ -76,6 +78,7 @@ pub const Code = struct { |
| 76 | 78 | code.instructions.deinit(gpa); |
| 77 | 79 | gpa.free(code.string_bytes); |
| 78 | 80 | gpa.free(code.extra); |
| 81 | gpa.free(code.decls); | |
| 79 | 82 | code.* = undefined; |
| 80 | 83 | } |
| 81 | 84 | |
| ... | ... | @@ -103,7 +106,7 @@ pub const Code = struct { |
| 103 | 106 | const stderr = std.io.getStdErr().writer(); |
| 104 | 107 | try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name }); |
| 105 | 108 | try writer.writeInstToStream(stderr, 0); |
| 106 | try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name }); | |
| 109 | try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name }); | |
| 107 | 110 | } |
| 108 | 111 | }; |
| 109 | 112 | |
| ... | ... | @@ -115,7 +118,7 @@ pub const Inst = struct { |
| 115 | 118 | data: Data, |
| 116 | 119 | |
| 117 | 120 | /// These names are used directly as the instruction names in the text format. |
| 118 | pub const Tag = enum { | |
| 121 | pub const Tag = enum(u8) { | |
| 119 | 122 | /// Arithmetic addition, asserts no integer overflow. |
| 120 | 123 | /// Uses the `pl_node` union field. Payload is `Bin`. |
| 121 | 124 | add, |
| ... | ... | @@ -274,10 +277,10 @@ pub const Inst = struct { |
| 274 | 277 | /// Uses the `node` union field. |
| 275 | 278 | dbg_stmt_node, |
| 276 | 279 | /// Represents a pointer to a global decl. |
| 277 | /// Uses the `decl` union field. | |
| 280 | /// Uses the `pl_node` union field. `payload_index` is into `decls`. | |
| 278 | 281 | decl_ref, |
| 279 | 282 | /// Equivalent to a decl_ref followed by load. |
| 280 | /// Uses the `decl` union field. | |
| 283 | /// Uses the `pl_node` union field. `payload_index` is into `decls`. | |
| 281 | 284 | decl_val, |
| 282 | 285 | /// Load the value from a pointer. Assumes `x.*` syntax. |
| 283 | 286 | /// Uses `un_node` field. AST node is the `x.*` syntax. |
| ... | ... | @@ -612,10 +615,6 @@ pub const Inst = struct { |
| 612 | 615 | // /// validated by the switch_br instruction. |
| 613 | 616 | // switch_range, |
| 614 | 617 | |
| 615 | comptime { | |
| 616 | assert(@sizeOf(Tag) == 1); | |
| 617 | } | |
| 618 | ||
| 619 | 618 | /// Returns whether the instruction is one of the control flow "noreturn" types. |
| 620 | 619 | /// Function calls do not count. |
| 621 | 620 | pub fn isNoReturn(tag: Tag) bool { |
| ... | ... | @@ -1099,7 +1098,6 @@ pub const Inst = struct { |
| 1099 | 1098 | } |
| 1100 | 1099 | }, |
| 1101 | 1100 | bin: Bin, |
| 1102 | decl: *Module.Decl, | |
| 1103 | 1101 | @"const": *TypedValue, |
| 1104 | 1102 | /// For strings which may contain null bytes. |
| 1105 | 1103 | str: struct { |
| ... | ... | @@ -1503,6 +1501,10 @@ const Writer = struct { |
| 1503 | 1501 | .typeof_peer, |
| 1504 | 1502 | => try self.writePlNodeMultiOp(stream, inst), |
| 1505 | 1503 | |
| 1504 | .decl_ref, | |
| 1505 | .decl_val, | |
| 1506 | => try self.writePlNodeDecl(stream, inst), | |
| 1507 | ||
| 1506 | 1508 | .as_node => try self.writeAs(stream, inst), |
| 1507 | 1509 | |
| 1508 | 1510 | .breakpoint, |
| ... | ... | @@ -1513,10 +1515,6 @@ const Writer = struct { |
| 1513 | 1515 | .repeat_inline, |
| 1514 | 1516 | => try self.writeNode(stream, inst), |
| 1515 | 1517 | |
| 1516 | .decl_ref, | |
| 1517 | .decl_val, | |
| 1518 | => try self.writeDecl(stream, inst), | |
| 1519 | ||
| 1520 | 1518 | .error_value, |
| 1521 | 1519 | .enum_literal, |
| 1522 | 1520 | => try self.writeStrTok(stream, inst), |
| ... | ... | @@ -1715,6 +1713,13 @@ const Writer = struct { |
| 1715 | 1713 | try self.writeSrc(stream, inst_data.src()); |
| 1716 | 1714 | } |
| 1717 | 1715 | |
| 1716 | fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { | |
| 1717 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; | |
| 1718 | const decl = self.code.decls[inst_data.payload_index]; | |
| 1719 | try stream.print("{s}) ", .{decl.name}); | |
| 1720 | try self.writeSrc(stream, inst_data.src()); | |
| 1721 | } | |
| 1722 | ||
| 1718 | 1723 | fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1719 | 1724 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1720 | 1725 | const extra = self.code.extraData(Inst.As, inst_data.payload_index).data; |
| ... | ... | @@ -1736,15 +1741,6 @@ const Writer = struct { |
| 1736 | 1741 | try self.writeSrc(stream, src); |
| 1737 | 1742 | } |
| 1738 | 1743 | |
| 1739 | fn writeDecl( | |
| 1740 | self: *Writer, | |
| 1741 | stream: anytype, | |
| 1742 | inst: Inst.Index, | |
| 1743 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | |
| 1744 | const decl = self.code.instructions.items(.data)[inst].decl; | |
| 1745 | try stream.print("{s})", .{decl.name}); | |
| 1746 | } | |
| 1747 | ||
| 1748 | 1744 | fn writeStrTok( |
| 1749 | 1745 | self: *Writer, |
| 1750 | 1746 | stream: anytype, |
test/stage2/test.zig+15-15| ... | ... | @@ -1112,21 +1112,21 @@ pub fn addCases(ctx: *TestContext) !void { |
| 1112 | 1112 | }); |
| 1113 | 1113 | } |
| 1114 | 1114 | |
| 1115 | //{ | |
| 1116 | // var case = ctx.obj("extern variable has no type", linux_x64); | |
| 1117 | // case.addError( | |
| 1118 | // \\comptime { | |
| 1119 | // \\ _ = foo; | |
| 1120 | // \\} | |
| 1121 | // \\extern var foo: i32; | |
| 1122 | // , &[_][]const u8{":2:9: error: unable to resolve comptime value"}); | |
| 1123 | // case.addError( | |
| 1124 | // \\export fn entry() void { | |
| 1125 | // \\ _ = foo; | |
| 1126 | // \\} | |
| 1127 | // \\extern var foo; | |
| 1128 | // , &[_][]const u8{":4:8: error: unable to infer variable type"}); | |
| 1129 | //} | |
| 1115 | { | |
| 1116 | var case = ctx.obj("extern variable has no type", linux_x64); | |
| 1117 | case.addError( | |
| 1118 | \\comptime { | |
| 1119 | \\ _ = foo; | |
| 1120 | \\} | |
| 1121 | \\extern var foo: i32; | |
| 1122 | , &[_][]const u8{":2:9: error: unable to resolve comptime value"}); | |
| 1123 | case.addError( | |
| 1124 | \\export fn entry() void { | |
| 1125 | \\ _ = foo; | |
| 1126 | \\} | |
| 1127 | \\extern var foo; | |
| 1128 | , &[_][]const u8{":4:8: error: unable to infer variable type"}); | |
| 1129 | } | |
| 1130 | 1130 | |
| 1131 | 1131 | //{ |
| 1132 | 1132 | // var case = ctx.exe("break/continue", linux_x64); |