diff --git a/src/AstGen.zig b/src/AstGen.zig index 91dea526dc..0540ca0146 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2013,7 +2013,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn }, .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, .top => unreachable, } @@ -2088,7 +2088,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) try parent_gz.addDefer(defer_scope.index, defer_scope.len); }, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .top => unreachable, } } @@ -2179,7 +2179,7 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke .local_val => scope = scope.cast(Scope.LocalVal).?.parent, .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => break, + .namespace, .enum_namespace => break, .top => unreachable, } } @@ -2729,7 +2729,7 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct { const have_err_payload = defer_scope.remapped_err_code != 0; need_err_code = need_err_code or have_err_payload; }, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -2799,7 +2799,7 @@ fn genDefers( .normal_only => continue, } }, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -2835,7 +2835,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v scope = s.parent; }, .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent, - .namespace => unreachable, + .namespace, .enum_namespace => unreachable, .top => unreachable, } } @@ -4278,7 +4278,7 @@ fn testDecl( .local_val, .local_ptr => unreachable, // a test cannot be in a local scope .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { if (found_already) |f| { @@ -4963,6 +4963,7 @@ fn containerDecl( defer block_scope.unstack(); _ = try astgen.scanDecls(&namespace, container_decl.ast.members); + namespace.base.tag = .enum_namespace; const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) try comptimeExpr(&block_scope, &namespace.base, .{ .rl = .{ .ty = .type_type } }, container_decl.ast.arg) @@ -4977,6 +4978,7 @@ fn containerDecl( for (container_decl.ast.members) |member_node| { if (member_node == counts.nonexhaustive_node) continue; + namespace.base.tag = .namespace; var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { .decl => continue, .field => |field| field, @@ -5010,6 +5012,7 @@ fn containerDecl( }, ); } + namespace.base.tag = .enum_namespace; const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, member.ast.value_expr); wip_members.appendToField(@enumToInt(tag_value_inst)); } @@ -7296,7 +7299,7 @@ fn localVarRef( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(name_str_index)) |i| { if (found_already) |f| { @@ -7308,7 +7311,7 @@ fn localVarRef( // We found a match but must continue looking for ambiguous references to decls. found_already = i; } - num_namespaces_out += 1; + if (s.tag == .namespace) num_namespaces_out += 1; capturing_namespace = ns; s = ns.parent; }, @@ -7935,7 +7938,7 @@ fn builtinCall( }, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, - .namespace => { + .namespace, .enum_namespace => { const ns = s.cast(Scope.Namespace).?; if (ns.decls.get(decl_name)) |i| { if (found_already) |f| { @@ -10547,6 +10550,12 @@ const Scope = struct { else => return null, } } + if (T == Namespace) { + switch (base.tag) { + .namespace, .enum_namespace => return @fieldParentPtr(T, "base", base), + else => return null, + } + } if (base.tag != T.base_tag) return null; @@ -10559,7 +10568,7 @@ const Scope = struct { .local_val => base.cast(LocalVal).?.parent, .local_ptr => base.cast(LocalPtr).?.parent, .defer_normal, .defer_error => base.cast(Defer).?.parent, - .namespace => base.cast(Namespace).?.parent, + .namespace, .enum_namespace => base.cast(Namespace).?.parent, .top => null, }; } @@ -10571,6 +10580,7 @@ const Scope = struct { defer_normal, defer_error, namespace, + enum_namespace, top, }; @@ -12247,7 +12257,7 @@ fn detectLocalShadowing( } s = local_ptr.parent; }, - .namespace => { + .namespace, .enum_namespace => { outer_scope = true; const ns = s.cast(Scope.Namespace).?; const decl_node = ns.decls.get(ident_name) orelse { @@ -12415,7 +12425,7 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. } s = local_ptr.parent; }, - .namespace => s = s.cast(Scope.Namespace).?.parent, + .namespace, .enum_namespace => s = s.cast(Scope.Namespace).?.parent, .gen_zir => s = s.cast(GenZir).?.parent, .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, .top => break, diff --git a/src/Module.zig b/src/Module.zig index 9c7d3ee885..0853a2e204 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1194,6 +1194,49 @@ pub const EnumFull = struct { .lazy = LazySrcLoc.nodeOffset(0), }; } + + pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc { + @setCold(true); + const owner_decl = mod.declPtr(e.owner_decl); + const file = owner_decl.getFileScope(); + const tree = file.getTree(mod.gpa) catch |err| { + // In this case we emit a warning + a less precise source location. + log.warn("unable to load {s}: {s}", .{ + file.sub_file_path, @errorName(err), + }); + return e.srcLoc(mod); + }; + const node = owner_decl.relativeToNodeIndex(0); + const node_tags = tree.nodes.items(.tag); + switch (node_tags[node]) { + .container_decl, + .container_decl_trailing, + => return queryFieldSrc(tree.*, query, file, tree.containerDecl(node)), + .container_decl_two, .container_decl_two_trailing => { + var buffer: [2]Ast.Node.Index = undefined; + return queryFieldSrc(tree.*, query, file, tree.containerDeclTwo(&buffer, node)); + }, + .container_decl_arg, + .container_decl_arg_trailing, + => return queryFieldSrc(tree.*, query, file, tree.containerDeclArg(node)), + + .tagged_union, + .tagged_union_trailing, + => return queryFieldSrc(tree.*, query, file, tree.taggedUnion(node)), + .tagged_union_two, .tagged_union_two_trailing => { + var buffer: [2]Ast.Node.Index = undefined; + return queryFieldSrc(tree.*, query, file, tree.taggedUnionTwo(&buffer, node)); + }, + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + => return queryFieldSrc(tree.*, query, file, tree.taggedUnionEnumTag(node)), + + .root => return queryFieldSrc(tree.*, query, file, tree.containerDeclRoot()), + + // This struct was generated using @Type + else => return e.srcLoc(mod), + } + } }; pub const Union = struct { @@ -3519,14 +3562,6 @@ pub fn deinit(mod: *Module) void { pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { const gpa = mod.gpa; { - if (mod.failed_decls.contains(decl_index)) { - blk: { - const errs = mod.comp.getAllErrorsAlloc() catch break :blk; - for (errs.list) |err| Compilation.AllErrors.Message.renderToStdErr(err, .no_color); - } - // TODO restore test case triggering this panic - @panic("Zig compiler bug: attempted to destroy declaration with an attached error"); - } const decl = mod.declPtr(decl_index); log.debug("destroy {*} ({s})", .{ decl, decl.name }); _ = mod.test_functions.swapRemove(decl_index); @@ -6179,7 +6214,7 @@ pub const PeerTypeCandidateSrc = union(enum) { const FieldSrcQuery = struct { index: usize, - range: enum { name, type, value, alignment }, + range: enum { name, type, value, alignment } = .name, }; fn queryFieldSrc( @@ -6749,3 +6784,25 @@ pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export { return &[0]*Export{}; } } + +pub const Feature = enum { + panic_fn, + panic_unwrap_error, + safety_check_formatted, + error_return_trace, + is_named_enum_value, + error_set_has_value, +}; + +pub fn backendSupportsFeature(mod: Module, feature: Feature) bool { + return switch (feature) { + .panic_fn => mod.comp.bin_file.options.target.ofmt == .c or + mod.comp.bin_file.options.use_llvm, + .panic_unwrap_error => mod.comp.bin_file.options.target.ofmt == .c or + mod.comp.bin_file.options.use_llvm, + .safety_check_formatted => mod.comp.bin_file.options.use_llvm, + .error_return_trace => mod.comp.bin_file.options.use_llvm, + .is_named_enum_value => mod.comp.bin_file.options.use_llvm, + .error_set_has_value => mod.comp.bin_file.options.use_llvm, + }; +} diff --git a/src/Sema.zig b/src/Sema.zig index 14e2345034..63f177e401 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1820,12 +1820,7 @@ fn analyzeAsType( } pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { - const backend_supports_error_return_tracing = - sema.mod.comp.bin_file.options.use_llvm; - if (!backend_supports_error_return_tracing) { - // TODO implement this feature in all the backends and then delete this branch - return; - } + if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; assert(!block.is_comptime); var err_trace_block = block.makeSubBlock(); @@ -2099,16 +2094,12 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); errdefer msg.destroy(sema.gpa); - const decl_index = container_ty.getOwnerDeclOrNull() orelse break :msg msg; - const decl = sema.mod.declPtr(decl_index); - const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); - const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x }; - - try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{}); + const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg; + const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{ + .index = field_index, + .range = .value, + }); + try sema.mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -2146,15 +2137,61 @@ fn addFieldErrNote( comptime format: []const u8, args: anytype, ) !void { + @setCold(true); const mod = sema.mod; const decl_index = container_ty.getOwnerDecl(); const decl = mod.declPtr(decl_index); - const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; + + const field_src = blk: { + const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { + log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); + break :blk decl.srcLoc(); + }; + + const container_node = decl.relativeToNodeIndex(0); + const node_tags = tree.nodes.items(.tag); + var buffer: [2]std.zig.Ast.Node.Index = undefined; + const container_decl = switch (node_tags[container_node]) { + .root => tree.containerDeclRoot(), + .container_decl, + .container_decl_trailing, + => tree.containerDecl(container_node), + .container_decl_two, + .container_decl_two_trailing, + => tree.containerDeclTwo(&buffer, container_node), + .container_decl_arg, + .container_decl_arg_trailing, + => tree.containerDeclArg(container_node), + .tagged_union, + .tagged_union_trailing, + => tree.taggedUnion(container_node), + .tagged_union_two, + .tagged_union_two_trailing, + => tree.taggedUnionTwo(&buffer, container_node), + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + => tree.taggedUnionEnumTag(container_node), + else => break :blk decl.srcLoc(), + }; + + var it_index: usize = 0; + for (container_decl.ast.members) |member_node| { + switch (node_tags[member_node]) { + .container_field_init, + .container_field_align, + .container_field, + => { + if (it_index == field_index) { + break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node)); + } + it_index += 1; + }, + else => continue, + } + } + unreachable; }; - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index); - try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args); + try mod.errNoteNonLazy(field_src, parent, format, args); } fn errMsg( @@ -2868,7 +2905,7 @@ fn zirEnumDecl( .inlining = null, .is_comptime = true, }; - defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions + defer enum_block.instructions.deinit(sema.gpa); if (body.len != 0) { try sema.analyzeBody(&enum_block, body); @@ -2934,13 +2971,12 @@ fn zirEnumDecl( const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); if (gop_field.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_tag_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_field.index); + const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy; const msg = msg: { const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name}); errdefer msg.destroy(gpa); - try sema.errNote(block, other_tag_src, msg, "other field here", .{}); + try sema.errNote(block, other_field_src, msg, "other field here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -2949,10 +2985,18 @@ fn zirEnumDecl( if (has_tag_value) { const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; - // TODO: if we need to report an error here, use a source location - // that points to this default value expression rather than the struct. - // But only resolve the source location if we need to emit a compile error. - const tag_val = (try sema.resolveInstConst(block, src, tag_val_ref, "enum tag value must be comptime-known")).val; + const tag_inst = try sema.resolveInst(tag_val_ref); + const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) { + error.NeededSourceLocation => { + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; + _ = try sema.resolveConstValue(block, value_src, tag_inst, "enum tag value must be comptime-known"); + unreachable; + }, + else => |e| return e, + }; last_tag_val = tag_val; const copied_tag_val = try tag_val.copy(decl_arena_allocator); const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ @@ -2960,11 +3004,13 @@ fn zirEnumDecl( .mod = mod, }); if (gop_val.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; const msg = msg: { - const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); + const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); errdefer msg.destroy(gpa); try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -2983,9 +3029,8 @@ fn zirEnumDecl( .mod = mod, }); if (gop_val.found_existing) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, gop_val.index); + const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; const msg = msg: { const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); errdefer msg.destroy(gpa); @@ -3003,9 +3048,11 @@ fn zirEnumDecl( } if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) { - const tree = try sema.getAstTree(block); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); - const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{ + const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = if (has_tag_value) .value else .name, + }).lazy; + const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), }); return sema.failWithOwnedErrorMsg(msg); @@ -3319,8 +3366,6 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index operand_ty.childType() else operand_ty; - // TODO this should be validated in a more generic instruction that is - // emitted for all ifs and whiles with an error union condition. if (err_union_ty.zigTypeTag() != .ErrorUnion) return; const payload_ty = err_union_ty.errorUnionPayload().zigTypeTag(); if (payload_ty != .Void and payload_ty != .NoReturn) { @@ -5908,9 +5953,8 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { const src = sema.src; - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; - if (!backend_supports_error_return_tracing or !sema.mod.comp.bin_file.options.error_return_tracing) - return .none; + if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none; + if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none; if (block.is_comptime) return .none; @@ -6148,8 +6192,7 @@ fn zirCall( if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn) input_is_error = false; // input was an error type, but no errorable fn's were actually called - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; - if (backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing and + if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) { const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: { @@ -7183,6 +7226,7 @@ fn instantiateGenericCall( return err; }, else => { + assert(mod.monomorphed_funcs.remove(new_module_func)); { errdefer new_decl_arena.deinit(); try new_decl.finalizeNewArena(&new_decl_arena); @@ -7936,11 +7980,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A try sema.requireRuntimeBlock(block, src, operand_src); const result = try block.addTyOp(.intcast, dest_ty, operand); - if (block.wantSafety() and - !dest_ty.isNonexhaustiveEnum() and - // TODO instead of "use_llvm", check a different condition so that backends - // can advertise themselves as supporting these extra AIR instructions for safety. - sema.mod.comp.bin_file.options.use_llvm) + if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and + sema.mod.backendSupportsFeature(.is_named_enum_value)) { const ok = try block.addUnOp(.is_named_enum_value, result); try sema.addSafetyCheck(block, ok, .invalid_enum_value); @@ -10658,8 +10699,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); } - const backend_supports_is_named_enum = sema.mod.comp.bin_file.options.use_llvm; - if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { if (empty_enum) { return Air.Inst.Ref.void_value; @@ -10670,7 +10709,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { return Air.Inst.Ref.unreachable_value; } - if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and + if (sema.mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) { try sema.zirDbgStmt(block, cond_dbg_node_index); @@ -11140,7 +11179,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError case_block.wip_capture_scope = wip_captures.scope; case_block.inline_case_capture = .none; - if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and + if (sema.mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) { try sema.zirDbgStmt(&case_block, cond_dbg_node_index); @@ -11453,10 +11492,7 @@ fn validateSwitchNoRange( } fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { - const this_feature_is_implemented_in_the_backend = - sema.mod.comp.bin_file.options.use_llvm; - - if (!this_feature_is_implemented_in_the_backend) return false; + if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false; const tags = sema.code.instructions.items(.tag); for (body) |inst| { @@ -16970,20 +17006,17 @@ fn retWithErrTracing( } fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { - // TODO implement this feature in all the backends and then delete this check. - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; + if (!sema.mod.backendSupportsFeature(.error_return_trace)) return false; return fn_ret_ty.isError() and - sema.mod.comp.bin_file.options.error_return_tracing and - backend_supports_error_return_tracing; + sema.mod.comp.bin_file.options.error_return_tracing; } fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index; - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; - const ok = backend_supports_error_return_tracing and sema.mod.comp.bin_file.options.error_return_tracing; - if (!ok) return; + if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; + if (!sema.mod.comp.bin_file.options.error_return_tracing) return; // This is only relevant at runtime. if (block.is_comptime or block.is_typeof) return; @@ -17005,11 +17038,9 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) // This is only relevant at runtime. if (start_block.is_comptime or start_block.is_typeof) return; - const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; - const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and - sema.mod.comp.bin_file.options.error_return_tracing and - backend_supports_error_return_tracing; - if (!ok) return; + if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; + if (!sema.owner_func.?.calls_or_awaits_errorable_fn) return; + if (!sema.mod.comp.bin_file.options.error_return_tracing) return; const tracy = trace(@src()); defer tracy.end(); @@ -17988,14 +18019,10 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); - // TODO implement this feature in all the backends and then delete this check. - const backend_supports_error_return_tracing = - sema.mod.comp.bin_file.options.use_llvm; - if (sema.owner_func != null and sema.owner_func.?.calls_or_awaits_errorable_fn and sema.mod.comp.bin_file.options.error_return_tracing and - backend_supports_error_return_tracing) + sema.mod.backendSupportsFeature(.error_return_trace)) { return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); } @@ -18175,7 +18202,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.addStrLit(block, field_name); } try sema.requireRuntimeBlock(block, src, operand_src); - if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) { + if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { const ok = try block.addUnOp(.is_named_enum_value, casted_operand); try sema.addSafetyCheck(block, ok, .invalid_enum_value); } @@ -19469,7 +19496,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat } try sema.requireRuntimeBlock(block, src, operand_src); - if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) { + if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.backendSupportsFeature(.error_set_has_value)) { const err_int_inst = try block.addBitCast(Type.err_int, operand); const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); try sema.addSafetyCheck(block, ok, .invalid_error_code); @@ -21596,7 +21623,7 @@ fn zirVarExtended( .owner_decl = sema.owner_decl_index, .init = init_val, .is_extern = small.is_extern, - .is_mutable = true, // TODO get rid of this unused field + .is_mutable = true, .is_threadlocal = small.is_threadlocal, .is_weak_linkage = false, .lib_name = null, @@ -22075,7 +22102,7 @@ fn zirBuiltinExtern( .owner_decl = sema.owner_decl_index, .init = Value.initTag(.unreachable_value), .is_extern = true, - .is_mutable = false, // TODO get rid of this unused field + .is_mutable = false, .is_threadlocal = options.is_thread_local, .is_weak_linkage = options.linkage == .Weak, .lib_name = null, @@ -22658,11 +22685,7 @@ fn panicWithMsg( const mod = sema.mod; const arena = sema.arena; - const this_feature_is_implemented_in_the_backend = - mod.comp.bin_file.options.target.ofmt == .c or - mod.comp.bin_file.options.use_llvm; - if (!this_feature_is_implemented_in_the_backend) { - // TODO implement this feature in all the backends and then delete this branch + if (!mod.backendSupportsFeature(.panic_fn)) { _ = try block.addNoOp(.breakpoint); _ = try block.addNoOp(.unreach); return; @@ -22711,11 +22734,7 @@ fn panicUnwrapError( defer fail_block.instructions.deinit(gpa); { - const this_feature_is_implemented_in_the_backend = - sema.mod.comp.bin_file.options.use_llvm; - - if (!this_feature_is_implemented_in_the_backend) { - // TODO implement this feature in all the backends and then delete this branch + if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { _ = try fail_block.addNoOp(.breakpoint); _ = try fail_block.addNoOp(.unreach); } else { @@ -22841,18 +22860,12 @@ fn safetyCheckFormatted( defer fail_block.instructions.deinit(gpa); - { - const this_feature_is_implemented_in_the_backend = - sema.mod.comp.bin_file.options.use_llvm; - - if (!this_feature_is_implemented_in_the_backend) { - // TODO implement this feature in all the backends and then delete this branch - _ = try fail_block.addNoOp(.breakpoint); - _ = try fail_block.addNoOp(.unreach); - } else { - const panic_fn = try sema.getBuiltin(func); - _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null); - } + if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { + _ = try fail_block.addNoOp(.breakpoint); + _ = try fail_block.addNoOp(.unreach); + } else { + const panic_fn = try sema.getBuiltin(func); + _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null); } try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } @@ -24517,7 +24530,7 @@ fn coerceExtra( return block.addBitCast(dest_ty, inst); } - const is_undef = if (maybe_inst_val) |val| val.isUndef() else false; + const is_undef = inst_ty.zigTypeTag() == .Undefined; switch (dest_ty.zigTypeTag()) { .Optional => optional: { @@ -30662,14 +30675,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); + const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); errdefer msg.destroy(gpa); const prev_field_index = struct_obj.fields.getIndex(field_name).?; - const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); - try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); + const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }); + try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); break :msg msg; }; @@ -30699,34 +30711,51 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void // so that init values may depend on type layout. const bodies_index = extra_index; - for (fields) |zir_field, i| { - // TODO emit compile errors for invalid field types - // such as arrays and pointers inside packed structs. + for (fields) |zir_field, field_i| { const field_ty: Type = ty: { if (zir_field.type_ref != .none) { - // TODO: if we need to report an error here, use a source location - // that points to this type expression rather than the struct. - // But only resolve the source location if we need to emit a compile error. - break :ty try sema.resolveType(&block_scope, src, zir_field.type_ref); + break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + _ = try sema.resolveType(&block_scope, ty_src, zir_field.type_ref); + unreachable; + }, + else => |e| return e, + }; } assert(zir_field.type_body_len != 0); const body = zir.extra[extra_index..][0..zir_field.type_body_len]; extra_index += body.len; const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); - break :ty try sema.analyzeAsType(&block_scope, src, ty_ref); + break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + _ = try sema.analyzeAsType(&block_scope, ty_src, ty_ref); + unreachable; + }, + else => |e| return e, + }; }; if (field_ty.tag() == .generic_poison) { return error.GenericPoison; } - const field = &struct_obj.fields.values()[i]; + const field = &struct_obj.fields.values()[field_i]; field.ty = try field_ty.copy(decl_arena_allocator); if (field_ty.zigTypeTag() == .Opaque) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); - const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, field_ty); @@ -30736,9 +30765,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void } if (field_ty.zigTypeTag() == .NoReturn) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, i); - const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{}); + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + const msg = try sema.errMsg(&block_scope, ty_src, "struct fields cannot be 'noreturn'", .{}); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, field_ty); @@ -30748,12 +30779,14 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void } if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); - const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }); + const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); errdefer msg.destroy(sema.gpa); - try sema.explainWhyTypeIsNotExtern(msg, fields_src.toSrcLoc(decl), field.ty, .struct_field); + try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); try sema.addDeclaredHereNote(msg, field.ty); break :msg msg; @@ -30761,12 +30794,14 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void return sema.failWithOwnedErrorMsg(msg); } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); - const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); + const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }); + const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); errdefer msg.destroy(sema.gpa); - try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field.ty); + try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); try sema.addDeclaredHereNote(msg, field.ty); break :msg msg; @@ -30778,7 +30813,17 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void const body = zir.extra[extra_index..][0..zir_field.align_body_len]; extra_index += body.len; const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); - field.abi_align = try sema.analyzeAsAlign(&block_scope, src, align_ref); + field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const align_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .alignment, + }).lazy; + _ = try sema.analyzeAsAlign(&block_scope, align_src, align_ref); + unreachable; + }, + else => |e| return e, + }; } extra_index += zir_field.init_body_len; @@ -30788,26 +30833,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void if (any_inits) { extra_index = bodies_index; - for (fields) |zir_field, i| { + for (fields) |zir_field, field_i| { extra_index += zir_field.type_body_len; extra_index += zir_field.align_body_len; if (zir_field.init_body_len > 0) { const body = zir.extra[extra_index..][0..zir_field.init_body_len]; extra_index += body.len; const init = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); - const field = &struct_obj.fields.values()[i]; + const field = &struct_obj.fields.values()[field_i]; const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { error.NeededSourceLocation => { - const tree = try sema.getAstTree(&block_scope); - const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i); + const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; _ = try sema.coerce(&block_scope, field.ty, init, init_src); unreachable; }, else => |e| return e, }; const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { - const tree = try sema.getAstTree(&block_scope); - const init_src = containerFieldInitSrcLoc(decl, tree.*, 0, i); + const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); }; field.default_val = try default_val.copy(decl_arena_allocator); @@ -31023,9 +31072,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { if (enum_value_map) |map| { const copied_val = if (tag_ref != .none) blk: { - const tag_src = src; // TODO better source location - const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, tag_src); - const val = try sema.resolveConstValue(&block_scope, tag_src, coerced, "enum tag value must be comptime-known"); + const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const val_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .value, + }).lazy; + _ = try sema.semaUnionFieldVal(&block_scope, val_src, int_tag_ty, tag_ref); + unreachable; + }, + else => |e| return e, + }; last_tag_val = val; // This puts the memory into the union arena, not the enum arena, but @@ -31045,9 +31102,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { .mod = mod, }); if (gop.found_existing) { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(sema.mod.declPtr(block_scope.src_decl), tree.*, src.node_offset.x, field_i); - const other_field_src = enumFieldSrcLoc(sema.mod.declPtr(block_scope.src_decl), tree.*, src.node_offset.x, gop.index); + const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; + const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy; const msg = msg: { const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)}); errdefer msg.destroy(gpa); @@ -31069,10 +31125,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { else if (field_type_ref == .none) Type.initTag(.noreturn) else - // TODO: if we need to report an error here, use a source location - // that points to this type expression rather than the union. - // But only resolve the source location if we need to emit a compile error. - try sema.resolveType(&block_scope, src, field_type_ref); + sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + _ = try sema.resolveType(&block_scope, ty_src, field_type_ref); + unreachable; + }, + else => |e| return e, + }; if (field_ty.tag() == .generic_poison) { return error.GenericPoison; @@ -31081,13 +31144,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); + const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); errdefer msg.destroy(gpa); const prev_field_index = union_obj.fields.getIndex(field_name).?; - const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index); + const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy; try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); try sema.errNote(&block_scope, src, msg, "union declared here", .{}); break :msg msg; @@ -31099,9 +31161,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { const enum_has_field = names.orderedRemove(field_name); if (!enum_has_field) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); - const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); + const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_obj.tag_ty); break :msg msg; @@ -31112,9 +31176,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { if (field_ty.zigTypeTag() == .Opaque) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); - const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); + const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }).lazy; + const msg = try sema.errMsg(&block_scope, ty_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, field_ty); @@ -31124,12 +31190,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); - const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); + const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }); + const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); errdefer msg.destroy(sema.gpa); - try sema.explainWhyTypeIsNotExtern(msg, field_src.toSrcLoc(decl), field_ty, .union_field); + try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field); try sema.addDeclaredHereNote(msg, field_ty); break :msg msg; @@ -31137,12 +31205,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { return sema.failWithOwnedErrorMsg(msg); } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { const msg = msg: { - const tree = try sema.getAstTree(&block_scope); - const fields_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); - const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); + const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .type, + }); + const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); errdefer msg.destroy(sema.gpa); - try sema.explainWhyTypeIsNotPacked(msg, fields_src.toSrcLoc(decl), field_ty); + try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); try sema.addDeclaredHereNote(msg, field_ty); break :msg msg; @@ -31156,10 +31226,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { }; if (align_ref != .none) { - // TODO: if we need to report an error here, use a source location - // that points to this alignment expression rather than the struct. - // But only resolve the source location if we need to emit a compile error. - gop.value_ptr.abi_align = try sema.resolveAlign(&block_scope, src, align_ref); + gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { + error.NeededSourceLocation => { + const align_src = union_obj.fieldSrcLoc(sema.mod, .{ + .index = field_i, + .range = .alignment, + }).lazy; + _ = try sema.resolveAlign(&block_scope, align_src, align_ref); + unreachable; + }, + else => |e| return e, + }; } else { gop.value_ptr.abi_align = 0; } @@ -31184,6 +31261,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } } +fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value { + const coerced = try sema.coerce(block, int_tag_ty, tag_ref, src); + return sema.resolveConstValue(block, src, coerced, "enum tag value must be comptime-known"); +} + fn generateUnionTagTypeNumbered( sema: *Sema, block: *Block, @@ -31607,102 +31689,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { } } -fn getAstTree(sema: *Sema, block: *Block) CompileError!*const std.zig.Ast { - return block.namespace.file_scope.getTree(sema.gpa) catch |err| { - log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; -} - -fn enumFieldSrcLoc( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) LazySrcLoc { - @setCold(true); - const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse - return LazySrcLoc.nodeOffset(0); - return decl.nodeSrcLoc(field_node); -} - -fn containerFieldInitSrcLoc( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) LazySrcLoc { - @setCold(true); - const node_tags = tree.nodes.items(.tag); - const field_node = containerFieldNode(decl, tree, node_offset, field_index) orelse - return LazySrcLoc.nodeOffset(0); - const node_data = tree.nodes.items(.data)[field_node]; - - const init_node = switch (node_tags[field_node]) { - .container_field_init => node_data.rhs, - .container_field => blk: { - const extra_data = tree.extraData(node_data.rhs, std.zig.Ast.Node.ContainerField); - break :blk extra_data.value_expr; - }, - else => unreachable, - }; - - return decl.nodeSrcLoc(init_node); -} - -fn containerFieldNode( - decl: *Decl, - tree: std.zig.Ast, - node_offset: i32, - field_index: usize, -) ?std.zig.Ast.Node.Index { - @setCold(true); - const enum_node = decl.relativeToNodeIndex(node_offset); - const node_tags = tree.nodes.items(.tag); - var buffer: [2]std.zig.Ast.Node.Index = undefined; - const container_decl = switch (node_tags[enum_node]) { - .root => tree.containerDeclRoot(), - - .container_decl, - .container_decl_trailing, - => tree.containerDecl(enum_node), - - .container_decl_two, - .container_decl_two_trailing, - => tree.containerDeclTwo(&buffer, enum_node), - - .container_decl_arg, - .container_decl_arg_trailing, - => tree.containerDeclArg(enum_node), - - .tagged_union, - .tagged_union_trailing, - => tree.taggedUnion(enum_node), - .tagged_union_two, - .tagged_union_two_trailing, - => tree.taggedUnionTwo(&buffer, enum_node), - .tagged_union_enum_tag, - .tagged_union_enum_tag_trailing, - => tree.taggedUnionEnumTag(enum_node), - - else => return null, - }; - var it_index: usize = 0; - for (container_decl.ast.members) |member_node| { - switch (node_tags[member_node]) { - .container_field_init, - .container_field_align, - .container_field, - => { - if (it_index == field_index) return member_node; - it_index += 1; - }, - - else => continue, - } - } else unreachable; -} - /// Returns the type of the AIR instruction. fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { return sema.getTmpAir().typeOf(inst); @@ -31792,14 +31778,6 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int)); } -fn addBool(sema: *Sema, ty: Type, boolean: bool) CompileError!Air.Inst.Ref { - return switch (ty.zigTypeTag()) { - .Vector => sema.addConstant(ty, try Value.Tag.repeated.create(sema.arena, Value.makeBool(boolean))), - .Bool => try sema.resolveInst(if (boolean) .bool_true else .bool_false), - else => unreachable, - }; -} - fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { return sema.addConstant(ty, Value.undef); } @@ -32443,27 +32421,6 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { return Value.fromBigInt(sema.arena, result_bigint.toConst()); } -/// Supports both (vectors of) floats and ints; handles undefined scalars. -fn numberAddWrap( - sema: *Sema, - lhs: Value, - rhs: Value, - ty: Type, -) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - var lhs_buf: Value.ElemValueBuffer = undefined; - var rhs_buf: Value.ElemValueBuffer = undefined; - const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); - const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); - scalar.* = try sema.numberAddWrapScalar(lhs_elem, rhs_elem, ty.scalarType()); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.numberAddWrapScalar(lhs, rhs, ty); -} - /// Supports both floats and ints; handles undefined. fn numberAddWrapScalar( sema: *Sema, @@ -32522,27 +32479,6 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { return Value.fromBigInt(sema.arena, result_bigint.toConst()); } -/// Supports both (vectors of) floats and ints; handles undefined scalars. -fn numberSubWrap( - sema: *Sema, - lhs: Value, - rhs: Value, - ty: Type, -) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try sema.arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - var lhs_buf: Value.ElemValueBuffer = undefined; - var rhs_buf: Value.ElemValueBuffer = undefined; - const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); - const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); - scalar.* = try sema.numberSubWrapScalar(lhs_elem, rhs_elem, ty.scalarType()); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.numberSubWrapScalar(lhs, rhs, ty); -} - /// Supports both floats and ints; handles undefined. fn numberSubWrapScalar( sema: *Sema, diff --git a/src/Zir.zig b/src/Zir.zig index ffe1f4c345..3f2e935050 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -100,8 +100,7 @@ pub fn nullTerminatedString(code: Zir, index: usize) [:0]const u8 { pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref { const raw_slice = code.extra[start..][0..len]; - // TODO we should be able to directly `@ptrCast` the slice to the other slice type. - return @ptrCast([*]Inst.Ref, raw_slice.ptr)[0..len]; + return @ptrCast([]Inst.Ref, raw_slice); } pub fn hasCompileErrors(code: Zir) bool { diff --git a/src/main.zig b/src/main.zig index 15207a57e1..ba82efc294 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3454,8 +3454,7 @@ fn runOrTest( } else if (watch) { warn("process exited with code {d}", .{code}); } else { - // TODO https://github.com/ziglang/zig/issues/6342 - process.exit(1); + process.exit(code); } }, else => { diff --git a/src/type.zig b/src/type.zig index 632be95438..2481423cb0 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1236,7 +1236,7 @@ pub const Type = extern union { // we can't hash these based on tags because they wouldn't match the expanded version. .type_info => unreachable, // needed to resolve the type before now - .bound_fn => unreachable, // TODO delete from the language + .bound_fn => unreachable, .var_args_param => unreachable, // can be any type } } @@ -3272,7 +3272,7 @@ pub const Type = extern union { .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer .function => unreachable, // represents machine code; not a pointer .@"opaque" => unreachable, // no size available - .bound_fn => unreachable, // TODO remove from the language + .bound_fn => unreachable, .noreturn => unreachable, .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, @@ -4088,47 +4088,6 @@ pub const Type = extern union { } } - /// Returns if type can be used for a runtime variable - pub fn isValidVarType(self: Type, is_extern: bool) bool { - var ty = self; - while (true) switch (ty.zigTypeTag()) { - .Bool, - .Int, - .Float, - .ErrorSet, - .Enum, - .Frame, - .AnyFrame, - => return true, - - .Opaque => return is_extern, - .ComptimeFloat, - .ComptimeInt, - .EnumLiteral, - .NoReturn, - .Type, - .Void, - .Undefined, - .Null, - => return false, - - .Optional => { - var buf: Payload.ElemType = undefined; - return ty.optionalChild(&buf).isValidVarType(is_extern); - }, - .Pointer, .Array, .Vector => ty = ty.elemType(), - .ErrorUnion => ty = ty.errorUnionPayload(), - - .Fn => @panic("TODO fn isValidVarType"), - .Struct => { - // TODO this is not always correct; introduce lazy value mechanism - // and here we need to force a resolve of "type requires comptime". - return true; - }, - .Union => @panic("TODO union isValidVarType"), - }; - } - /// For *[N]T, returns [N]T. /// For *T, returns T. /// For [*]T, returns T. @@ -5434,7 +5393,6 @@ pub const Type = extern union { } /// Asserts the type is an enum or a union. - /// TODO support unions pub fn intTagType(ty: Type, buffer: *Payload.Bits) Type { switch (ty.tag()) { .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty, diff --git a/src/value.zig b/src/value.zig index eeb1228ebc..45b2bfd341 100644 --- a/src/value.zig +++ b/src/value.zig @@ -814,7 +814,6 @@ pub const Value = extern union { .float_80 => return out_stream.print("{}", .{val.castTag(.float_80).?.data}), .float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}), .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), - // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that .eu_payload => { try out_stream.writeAll("(eu_payload) "); val = val.castTag(.eu_payload).?.data; @@ -989,8 +988,7 @@ pub const Value = extern union { switch (val.tag()) { .enum_field_index => { const field_index = val.castTag(.enum_field_index).?.data; - // TODO should `@intToEnum` do this `@intCast` for you? - return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index)); + return @intToEnum(E, field_index); }, .the_only_possible_value => { const fields = std.meta.fields(E); diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index a398d5ec22..095f3b740b 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1185,3 +1185,13 @@ test "runtime int to enum with one possible value" { @compileError("test failed"); } } + +test "enum tag from a local variable" { + const S = struct { + fn Int(comptime Inner: type) type { + return enum(Inner) { _ }; + } + }; + const i = @intToEnum(S.Int(u32), 0); + try std.testing.expect(@enumToInt(i) == 0); +} diff --git a/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig b/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig index 3be57ac491..2a64326093 100644 --- a/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig +++ b/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig @@ -29,9 +29,9 @@ export fn d() void { // backend=stage2 // target=native // -// :3:5: error: opaque types have unknown size and therefore cannot be directly embedded in structs +// :3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs // :1:11: note: opaque declared here -// :7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions +// :7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions // :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs // :18:22: note: opaque declared here // :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs diff --git a/test/cases/compile_errors/enum_value_already_taken.zig b/test/cases/compile_errors/enum_value_already_taken.zig index 4d660dc1e0..733585a748 100644 --- a/test/cases/compile_errors/enum_value_already_taken.zig +++ b/test/cases/compile_errors/enum_value_already_taken.zig @@ -14,5 +14,5 @@ export fn entry() void { // backend=stage2 // target=native // -// :6:5: error: enum tag value 60 already taken +// :6:9: error: enum tag value 60 already taken // :4:5: note: other occurrence here diff --git a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig index d12bea66d7..6484e301a9 100644 --- a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig +++ b/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig @@ -39,7 +39,7 @@ export fn entry() void { // backend=stage2 // target=native // -// :31:5: error: extern structs cannot contain fields of type 'tmp.E' -// :31:5: note: enum tag type 'u9' is not extern compatible -// :31:5: note: only integers with power of two bits are extern compatible +// :31:8: error: extern structs cannot contain fields of type 'tmp.E' +// :31:8: note: enum tag type 'u9' is not extern compatible +// :31:8: note: only integers with power of two bits are extern compatible // :1:15: note: enum declared here diff --git a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig index 61073e9803..a83edb6289 100644 --- a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig +++ b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig @@ -11,7 +11,7 @@ export fn entry() void { // backend=stage2 // target=native // -// :3:5: error: extern structs cannot contain fields of type 'tmp.E' -// :3:5: note: enum tag type 'u31' is not extern compatible -// :3:5: note: only integers with power of two bits are extern compatible +// :3:8: error: extern structs cannot contain fields of type 'tmp.E' +// :3:8: note: enum tag type 'u31' is not extern compatible +// :3:8: note: only integers with power of two bits are extern compatible // :1:15: note: enum declared here diff --git a/test/cases/compile_errors/file_level_struct_invalid_field_type.zig b/test/cases/compile_errors/file_level_struct_invalid_field_type.zig new file mode 100644 index 0000000000..505bc814ed --- /dev/null +++ b/test/cases/compile_errors/file_level_struct_invalid_field_type.zig @@ -0,0 +1,17 @@ +const Parser = @This(); +fn Chunk() type { + return struct { + const Self = @This(); + }; +} +parser_chunk: Chunk, + +comptime { + _ = @sizeOf(@This()) + 1; +} + +// error +// backend=stage2 +// target=native +// +// :7:15: error: expected type 'type', found 'fn() type' diff --git a/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig b/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig new file mode 100644 index 0000000000..1d45ce86db --- /dev/null +++ b/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig @@ -0,0 +1,30 @@ +pub export fn entry1() void { + @setEvalBranchQuota(1001); + // Return type evaluation should inherit both the + // parent's branch quota and count meaning + // at least 2002 backwards branches are required. + comptime var i = 0; + inline while (i < 1000) : (i += 1) {} + _ = simple(10); +} +pub export fn entry2() void { + @setEvalBranchQuota(2001); + comptime var i = 0; + inline while (i < 1000) : (i += 1) {} + _ = simple(10); +} +fn simple(comptime n: usize) Type(n) { + return n; +} +fn Type(comptime n: usize) type { + if (n <= 1) return usize; + return Type(n - 1); +} + +// error +// backend=stage2 +// target=native +// +// :21:16: error: evaluation exceeded 1001 backwards branches +// :21:16: note: use @setEvalBranchQuota() to raise the branch limit from 1001 +// :16:34: note: called from here diff --git a/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig b/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig index 3dc9e64765..10e140d881 100644 --- a/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig +++ b/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig @@ -7,5 +7,5 @@ export fn testf(fluff: *stroo) void { _ = fluff; } // backend=stage2 // target=native // -// :2:5: error: extern structs cannot contain fields of type '?[*c]u8' -// :2:5: note: only pointer like optionals are extern compatible +// :2:10: error: extern structs cannot contain fields of type '?[*c]u8' +// :2:10: note: only pointer like optionals are extern compatible diff --git a/test/cases/compile_errors/noreturn_struct_field.zig b/test/cases/compile_errors/noreturn_struct_field.zig index 90b243c31d..3ce99849c9 100644 --- a/test/cases/compile_errors/noreturn_struct_field.zig +++ b/test/cases/compile_errors/noreturn_struct_field.zig @@ -9,4 +9,4 @@ comptime { // backend=stage2 // target=native // -// :2:5: error: struct fields cannot be 'noreturn' +// :2:8: error: struct fields cannot be 'noreturn' diff --git a/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig b/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig index db778408bf..4f957a827c 100644 --- a/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig +++ b/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig @@ -12,9 +12,9 @@ comptime { // backend=stage2 // target=native // -// :2:5: error: extern structs cannot contain fields of type 'fn() callconv(.C) void' -// :2:5: note: type has no guaranteed in-memory representation -// :2:5: note: use '*const ' to make a function pointer type +// :2:8: error: extern structs cannot contain fields of type 'fn() callconv(.C) void' +// :2:8: note: type has no guaranteed in-memory representation +// :2:8: note: use '*const ' to make a function pointer type // :8:13: error: C pointers cannot point to non-C-ABI-compatible type '[4]fn() callconv(.C) void' // :8:13: note: type has no guaranteed in-memory representation // :8:13: note: use '*const ' to make a function pointer type diff --git a/test/cases/compile_errors/only_untyped_undef_coerces_to_all_types.zig b/test/cases/compile_errors/only_untyped_undef_coerces_to_all_types.zig new file mode 100644 index 0000000000..091c51ff3b --- /dev/null +++ b/test/cases/compile_errors/only_untyped_undef_coerces_to_all_types.zig @@ -0,0 +1,11 @@ +pub export fn entry() void { + const x: []u8 = undefined; + const y: f32 = x; + _ = y; +} + +// error +// backend=stage2 +// target=native +// +// :3:20: error: expected type 'f32', found '[]u8' diff --git a/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig b/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig index fd98db04c8..30b43ea8ca 100644 --- a/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig +++ b/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig @@ -70,22 +70,22 @@ export fn entry12() void { // backend=llvm // target=native // -// :3:9: error: packed structs cannot contain fields of type 'anyerror' -// :3:9: note: type has no guaranteed in-memory representation -// :8:9: error: packed structs cannot contain fields of type '[2]u24' -// :8:9: note: type has no guaranteed in-memory representation -// :13:9: error: packed structs cannot contain fields of type 'anyerror!u32' -// :13:9: note: type has no guaranteed in-memory representation -// :18:9: error: packed structs cannot contain fields of type 'tmp.S' -// :18:9: note: only packed structs layout are allowed in packed types +// :3:12: error: packed structs cannot contain fields of type 'anyerror' +// :3:12: note: type has no guaranteed in-memory representation +// :8:12: error: packed structs cannot contain fields of type '[2]u24' +// :8:12: note: type has no guaranteed in-memory representation +// :13:20: error: packed structs cannot contain fields of type 'anyerror!u32' +// :13:20: note: type has no guaranteed in-memory representation +// :18:12: error: packed structs cannot contain fields of type 'tmp.S' +// :18:12: note: only packed structs layout are allowed in packed types // :56:11: note: struct declared here -// :23:9: error: packed structs cannot contain fields of type 'tmp.U' -// :23:9: note: only packed unions layout are allowed in packed types +// :23:12: error: packed structs cannot contain fields of type 'tmp.U' +// :23:12: note: only packed unions layout are allowed in packed types // :59:18: note: union declared here -// :28:9: error: packed structs cannot contain fields of type '?anyerror' -// :28:9: note: type has no guaranteed in-memory representation -// :38:9: error: packed structs cannot contain fields of type 'fn() void' -// :38:9: note: type has no guaranteed in-memory representation -// :38:9: note: use '*const ' to make a function pointer type -// :65:28: error: packed structs cannot contain fields of type '[]u8' -// :65:28: note: slices have no guaranteed in-memory representation +// :28:12: error: packed structs cannot contain fields of type '?anyerror' +// :28:12: note: type has no guaranteed in-memory representation +// :38:12: error: packed structs cannot contain fields of type 'fn() void' +// :38:12: note: type has no guaranteed in-memory representation +// :38:12: note: use '*const ' to make a function pointer type +// :65:31: error: packed structs cannot contain fields of type '[]u8' +// :65:31: note: slices have no guaranteed in-memory representation diff --git a/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig b/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig index 97771e9b78..0db9d83dfb 100644 --- a/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig +++ b/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig @@ -15,6 +15,6 @@ export fn entry() void { // backend=stage2 // target=native // -// :6:5: error: packed unions cannot contain fields of type 'tmp.Foo' -// :6:5: note: only packed structs layout are allowed in packed types +// :6:8: error: packed unions cannot contain fields of type 'tmp.Foo' +// :6:8: note: only packed structs layout are allowed in packed types // :1:13: note: struct declared here diff --git a/test/cases/compile_errors/union_enum_field_does_not_match_enum.zig b/test/cases/compile_errors/union_enum_field_does_not_match_enum.zig index 9370207c59..3c1e2d53ef 100644 --- a/test/cases/compile_errors/union_enum_field_does_not_match_enum.zig +++ b/test/cases/compile_errors/union_enum_field_does_not_match_enum.zig @@ -18,5 +18,5 @@ export fn entry() void { // backend=stage2 // target=native // -// :10:5: error: no field named 'D' in enum 'tmp.Letter' +// :10:8: error: no field named 'D' in enum 'tmp.Letter' // :1:16: note: enum declared here diff --git a/test/cases/compile_errors/union_extra_field.zig b/test/cases/compile_errors/union_extra_field.zig index 6d1c644bc6..046286cbfa 100644 --- a/test/cases/compile_errors/union_extra_field.zig +++ b/test/cases/compile_errors/union_extra_field.zig @@ -16,5 +16,5 @@ export fn entry() usize { // error // target=native // -// :10:5: error: no field named 'd' in enum 'tmp.E' +// :10:8: error: no field named 'd' in enum 'tmp.E' // :1:11: note: enum declared here