diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 30 | ||||
| -rw-r--r-- | src/Autodoc.zig | 3 | ||||
| -rw-r--r-- | src/Compilation.zig | 7 | ||||
| -rw-r--r-- | src/InternPool.zig | 30 | ||||
| -rw-r--r-- | src/Module.zig | 55 | ||||
| -rw-r--r-- | src/Sema.zig | 377 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 11 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 65 | ||||
| -rw-r--r-- | src/translate_c.zig | 29 |
9 files changed, 374 insertions, 233 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 0cf9c75c55..bff56614fe 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -8384,10 +8384,7 @@ fn builtinCall( local_val.used = ident_token; _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ .operand = local_val.inst, - // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - .options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]), + .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]), }); return rvalue(gz, ri, .void_value, node); } @@ -8402,10 +8399,7 @@ fn builtinCall( const loaded = try gz.addUnNode(.load, local_ptr.ptr, node); _ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{ .operand = loaded, - // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - .options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]), + .options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]), }); return rvalue(gz, ri, .void_value, node); } @@ -8439,10 +8433,7 @@ fn builtinCall( }, else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}), } - // TODO: the result location here should be `.{ .coerced_ty = .export_options_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .export_options_type } }, params[1]); _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ .namespace = namespace, .decl_name = decl_name, @@ -8452,10 +8443,7 @@ fn builtinCall( }, .@"extern" => { const type_inst = try typeExpr(gz, scope, params[0]); - // TODO: the result location here should be `.{ .coerced_ty = .extern_options_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .extern_options_type } }, params[1]); const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = type_inst, @@ -8559,10 +8547,7 @@ fn builtinCall( // zig fmt: on .Type => { - // TODO: the result location here should be `.{ .coerced_ty = .type_info_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - const operand = try expr(gz, scope, .{ .rl = .none }, params[0]); + const operand = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .type_info_type } }, params[0]); const gpa = gz.astgen.gpa; @@ -8834,10 +8819,7 @@ fn builtinCall( }, .prefetch => { const ptr = try expr(gz, scope, .{ .rl = .none }, params[0]); - // TODO: the result location here should be `.{ .coerced_ty = .preftech_options_type }`, but - // that currently hits assertions in Sema due to type resolution issues. - // See #16603 - const options = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); + const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .prefetch_options_type } }, params[1]); _ = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = ptr, diff --git a/src/Autodoc.zig b/src/Autodoc.zig index d865a43225..92cfac6b51 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -5537,9 +5537,8 @@ fn findGuidePaths(self: *Autodoc, file: *File, str: []const u8) ![]const u8 { fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8, section: *Section) !void { if (guide_path.len == 0) return error.MissingAutodocGuideName; - const cur_mod_dir_path = file.pkg.root_src_directory.path orelse "."; const resolved_path = try std.fs.path.resolve(self.arena, &[_][]const u8{ - cur_mod_dir_path, file.sub_file_path, "..", guide_path, + file.sub_file_path, "..", guide_path, }); var guide_file = try file.pkg.root_src_directory.handle.openFile(resolved_path, .{}); diff --git a/src/Compilation.zig b/src/Compilation.zig index 47e13ba85c..726862f231 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5175,10 +5175,13 @@ pub fn lockAndParseLldStderr(comp: *Compilation, comptime prefix: []const u8, st } pub fn dump_argv(argv: []const []const u8) void { + std.debug.getStderrMutex().lock(); + defer std.debug.getStderrMutex().unlock(); + const stderr = std.io.getStdErr().writer(); for (argv[0 .. argv.len - 1]) |arg| { - std.debug.print("{s} ", .{arg}); + nosuspend stderr.print("{s} ", .{arg}) catch return; } - std.debug.print("{s}\n", .{argv[argv.len - 1]}); + nosuspend stderr.print("{s}\n", .{argv[argv.len - 1]}) catch {}; } pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { diff --git a/src/InternPool.zig b/src/InternPool.zig index 178bc6870c..bde6c11256 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -7176,3 +7176,33 @@ fn unwrapCoercedFunc(ip: *const InternPool, i: Index) Index { else => unreachable, }; } + +/// Having resolved a builtin type to a real struct/union/enum (which is now at `resolverd_index`), +/// make `want_index` refer to this type instead. This invalidates `resolved_index`, so must be +/// called only when it is guaranteed that no reference to `resolved_index` exists. +pub fn resolveBuiltinType(ip: *InternPool, want_index: Index, resolved_index: Index) void { + assert(@intFromEnum(want_index) >= @intFromEnum(Index.first_type)); + assert(@intFromEnum(want_index) <= @intFromEnum(Index.last_type)); + + // Make sure the type isn't already resolved! + assert(ip.indexToKey(want_index) == .simple_type); + + // Make sure it's the same kind of type + assert((ip.zigTypeTagOrPoison(want_index) catch unreachable) == + (ip.zigTypeTagOrPoison(resolved_index) catch unreachable)); + + // Copy the data + const item = ip.items.get(@intFromEnum(resolved_index)); + ip.items.set(@intFromEnum(want_index), item); + + if (std.debug.runtime_safety) { + // Make the value unreachable - this is a weird value which will make (incorrect) existing + // references easier to spot + ip.items.set(@intFromEnum(resolved_index), .{ + .tag = .simple_value, + .data = @intFromEnum(SimpleValue.@"unreachable"), + }); + } else { + // TODO: add the index to a free-list for reuse + } +} diff --git a/src/Module.zig b/src/Module.zig index 06976ae49c..c19b742b54 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -770,9 +770,8 @@ pub const Decl = struct { /// Gets the namespace that this Decl creates by being a struct, union, /// enum, or opaque. - /// Only returns it if the Decl is the owner. - pub fn getOwnedInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { - if (!decl.owns_tv) return .none; + pub fn getInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { + if (!decl.has_tv) return .none; return switch (decl.val.ip_index) { .empty_struct_type => .none, .none => .none, @@ -786,11 +785,22 @@ pub const Decl = struct { }; } - /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. + /// Like `getInnerNamespaceIndex`, but only returns it if the Decl is the owner. + pub fn getOwnedInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { + if (!decl.owns_tv) return .none; + return decl.getInnerNamespaceIndex(mod); + } + + /// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer. pub fn getOwnedInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { return mod.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(mod)); } + /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. + pub fn getInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { + return mod.namespacePtrUnwrap(decl.getInnerNamespaceIndex(mod)); + } + pub fn dump(decl: *Decl) void { const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); std.debug.print("{s}:{d}:{d} name={d} status={s}", .{ @@ -4283,6 +4293,40 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { const zir = decl.getFileScope(mod).zir; const zir_datas = zir.instructions.items(.data); + // TODO: figure out how this works under incremental changes to builtin.zig! + const builtin_type_target_index: InternPool.Index = blk: { + const std_mod = mod.main_pkg.table.get("std").?; + if (decl.getFileScope(mod).pkg != std_mod) break :blk .none; + // We're in the std module. + const std_file = (try mod.importPkg(std_mod)).file; + const std_decl = mod.declPtr(std_file.root_decl.unwrap().?); + const std_namespace = std_decl.getInnerNamespace(mod).?; + const builtin_str = try mod.intern_pool.getOrPutString(gpa, "builtin"); + const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .mod = mod }) orelse break :blk .none); + const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :blk .none; + if (decl.src_namespace != builtin_namespace) break :blk .none; + // We're in builtin.zig. This could be a builtin we need to add to a specific InternPool index. + const decl_name = mod.intern_pool.stringToSlice(decl.name); + for ([_]struct { []const u8, InternPool.Index }{ + .{ "AtomicOrder", .atomic_order_type }, + .{ "AtomicRmwOp", .atomic_rmw_op_type }, + .{ "CallingConvention", .calling_convention_type }, + .{ "AddressSpace", .address_space_type }, + .{ "FloatMode", .float_mode_type }, + .{ "ReduceOp", .reduce_op_type }, + .{ "CallModifier", .call_modifier_type }, + .{ "PrefetchOptions", .prefetch_options_type }, + .{ "ExportOptions", .export_options_type }, + .{ "ExternOptions", .extern_options_type }, + .{ "Type", .type_info_type }, + }) |pair| { + if (std.mem.eql(u8, decl_name, pair[0])) { + break :blk pair[1]; + } + } + break :blk .none; + }; + decl.analysis = .in_progress; var analysis_arena = std.heap.ArenaAllocator.init(gpa); @@ -4304,6 +4348,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { .fn_ret_ty_ies = null, .owner_func_index = .none, .comptime_mutable_decls = &comptime_mutable_decls, + .builtin_type_target_index = builtin_type_target_index, }; defer sema.deinit(); @@ -4340,6 +4385,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); const body = zir.extra[extra.end..][0..extra.data.body_len]; const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; + // We'll do some other bits with the Sema. Clear the type target index just in case they analyze any type. + sema.builtin_type_target_index = .none; try wip_captures.finalize(); for (comptime_mutable_decls.items) |ct_decl_index| { const ct_decl = mod.declPtr(ct_decl_index); diff --git a/src/Sema.zig b/src/Sema.zig index e7d1df0ebb..396ef9a786 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -107,6 +107,10 @@ comptime_mutable_decls: *std.ArrayList(Decl.Index), /// one encountered, the conflicting source location can be shown. prev_stack_alignment_src: ?LazySrcLoc = null, +/// While analyzing a type which has a special InternPool index, this is set to the index at which +/// the struct/enum/union type created should be placed. Otherwise, it is `.none`. +builtin_type_target_index: InternPool.Index = .none, + const std = @import("std"); const math = std.math; const mem = std.mem; @@ -1956,8 +1960,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty)); // var st: StackTrace = undefined; - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); // st.instruction_addresses = &addrs; @@ -2890,10 +2894,17 @@ fn zirStructDecl( }); errdefer mod.destroyStruct(struct_index); - const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ - .index = struct_index.toOptional(), - .namespace = new_namespace_index.toOptional(), - } }); + const struct_ty = ty: { + const ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ + .index = struct_index.toOptional(), + .namespace = new_namespace_index.toOptional(), + } }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty); + break :ty sema.builtin_type_target_index; + } + break :ty ty; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer mod.intern_pool.remove(struct_ty); @@ -3084,18 +3095,25 @@ fn zirEnumDecl( if (bag != 0) break true; } else false; - const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ - .decl = new_decl_index, - .namespace = new_namespace_index.toOptional(), - .fields_len = fields_len, - .has_values = any_values, - .tag_mode = if (small.nonexhaustive) - .nonexhaustive - else if (tag_type_ref == .none) - .auto - else - .explicit, - }); + const incomplete_enum = incomplete_enum: { + var incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ + .decl = new_decl_index, + .namespace = new_namespace_index.toOptional(), + .fields_len = fields_len, + .has_values = any_values, + .tag_mode = if (small.nonexhaustive) + .nonexhaustive + else if (tag_type_ref == .none) + .auto + else + .explicit, + }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index); + incomplete_enum.index = sema.builtin_type_target_index; + } + break :incomplete_enum incomplete_enum; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); @@ -3336,17 +3354,24 @@ fn zirUnionDecl( }); errdefer mod.destroyUnion(union_index); - const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ - .index = union_index, - .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) - .tagged - else if (small.layout != .Auto) - .none - else switch (block.sema.mod.optimizeMode()) { - .Debug, .ReleaseSafe => .safety, - .ReleaseFast, .ReleaseSmall => .none, - }, - } }); + const union_ty = ty: { + const ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ + .index = union_index, + .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) + .tagged + else if (small.layout != .Auto) + .none + else switch (block.sema.mod.optimizeMode()) { + .Debug, .ReleaseSafe => .safety, + .ReleaseFast, .ReleaseSmall => .none, + }, + } }); + if (sema.builtin_type_target_index != .none) { + mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty); + break :ty sema.builtin_type_target_index; + } + break :ty ty; + }; // TODO: figure out InternPool removals for incremental compilation //errdefer mod.intern_pool.remove(union_ty); @@ -3473,8 +3498,8 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { defer tracy.end(); if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { - const fn_ret_ty = try sema.resolveTypeFields(sema.fn_ret_ty); - return sema.analyzeComptimeAlloc(block, fn_ret_ty, .none); + try sema.resolveTypeFields(sema.fn_ret_ty); + return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none); } const target = sema.mod.getTarget(); @@ -4371,7 +4396,7 @@ fn zirValidateArrayInitTy( return; }, .Struct => if (ty.isTuple(mod)) { - _ = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); const array_len = ty.arrayLen(mod); if (extra.init_count > array_len) { return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ @@ -6476,11 +6501,11 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref if (block.is_comptime) return .none; - const unresolved_stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { + const stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) { error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; - const stack_trace_ty = sema.resolveTypeFields(unresolved_stack_trace_ty) catch |err| switch (err) { + sema.resolveTypeFields(stack_trace_ty) catch |err| switch (err) { error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; @@ -6522,8 +6547,8 @@ fn popErrorReturnTrace( // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or // the result is comptime-known to be a non-error. Either way, pop unconditionally. - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); @@ -6548,8 +6573,8 @@ fn popErrorReturnTrace( defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); @@ -6671,8 +6696,8 @@ fn zirCall( // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only // need to clean-up our own trace if we were passed to a non-error-handling expression. if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) { - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index"); const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); @@ -8084,7 +8109,7 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const bin = sema.code.instructions.items(.data)[inst].bin; - const operand = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { + const indexable_ty = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { // Since this is a ZIR instruction that returns a type, encountering // generic poison should not result in a failed compilation, but the // generic poison type. This prevents unnecessary failures when @@ -8092,7 +8117,7 @@ fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr error.GenericPoison => return .generic_poison_type, else => |e| return e, }; - const indexable_ty = try sema.resolveTypeFields(operand); + try sema.resolveTypeFields(indexable_ty); assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction if (indexable_ty.zigTypeTag(mod) == .Struct) { const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod); @@ -8420,8 +8445,8 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { .Enum => operand, .Union => blk: { - const union_ty = try sema.resolveTypeFields(operand_ty); - const tag_ty = union_ty.unionTagType(mod) orelse { + try sema.resolveTypeFields(operand_ty); + const tag_ty = operand_ty.unionTagType(mod) orelse { return sema.fail( block, operand_src, @@ -9573,7 +9598,7 @@ fn finishFunc( // Make sure that StackTrace's fields are resolved so that the backend can // lower this fn type. const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - _ = try sema.resolveTypeFields(unresolved_stack_trace_ty); + try sema.resolveTypeFields(unresolved_stack_trace_ty); } return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty); @@ -10890,12 +10915,12 @@ fn switchCond( }, .Union => { - const union_ty = try sema.resolveTypeFields(operand_ty); - const enum_ty = union_ty.unionTagType(mod) orelse { + try sema.resolveTypeFields(operand_ty); + const enum_ty = operand_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); errdefer msg.destroy(sema.gpa); - if (union_ty.declSrcLocOrNull(mod)) |union_src| { + if (operand_ty.declSrcLocOrNull(mod)) |union_src| { try mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); } break :msg msg; @@ -12780,9 +12805,9 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; - const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); + const ty = try sema.resolveType(block, ty_src, extra.lhs); const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, "field name must be comptime-known"); - const ty = try sema.resolveTypeFields(unresolved_ty); + try sema.resolveTypeFields(ty); const ip = &mod.intern_pool; const has_field = hf: { @@ -16141,7 +16166,8 @@ fn analyzeCmpUnionTag( op: std.math.CompareOperator, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const union_ty = try sema.resolveTypeFields(sema.typeOf(un)); + const union_ty = sema.typeOf(un); + try sema.resolveTypeFields(union_ty); const union_tag_ty = union_ty.unionTagType(mod) orelse { const msg = msg: { const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); @@ -17278,11 +17304,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t union_field_ty_decl.val.toType(); }; - const union_ty = try sema.resolveTypeFields(ty); try sema.resolveTypeLayout(ty); // Getting alignment requires type layout - const layout = union_ty.containerLayout(mod); + const layout = ty.containerLayout(mod); - const union_fields = union_ty.unionFields(mod); + const union_fields = ty.unionFields(mod); const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); defer gpa.free(union_field_vals); @@ -17357,11 +17382,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const enum_tag_ty_val = try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(.type_type)).toIntern(), - .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, + .val = if (ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, } }); const container_layout_ty = t: { @@ -17429,18 +17454,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t struct_field_ty_decl.val.toType(); }; - const struct_ty = try sema.resolveTypeFields(ty); try sema.resolveTypeLayout(ty); // Getting alignment requires type layout - const layout = struct_ty.containerLayout(mod); + const layout = ty.containerLayout(mod); var struct_field_vals: []InternPool.Index = &.{}; defer gpa.free(struct_field_vals); fv: { - const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) { + const struct_type = switch (ip.indexToKey(ty.toIntern())) { .anon_struct_type => |tuple| { struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); for (struct_field_vals, 0..) |*struct_field_val, i| { - const anon_struct_type = ip.indexToKey(struct_ty.toIntern()).anon_struct_type; + const anon_struct_type = ip.indexToKey(ty.toIntern()).anon_struct_type; const field_ty = anon_struct_type.types[i]; const field_val = anon_struct_type.values[i]; const name_val = v: { @@ -17449,7 +17473,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // TODO: write something like getCoercedInts to avoid needing to dupe const bytes = if (tuple.names.len != 0) // https://github.com/ziglang/zig/issues/15709 - try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(struct_ty.toIntern()).anon_struct_type.names[i])) + try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(ty.toIntern()).anon_struct_type.names[i])) else try std.fmt.allocPrint(sema.arena, "{d}", .{i}); const new_decl_ty = try mod.arrayType(.{ @@ -17582,12 +17606,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod)); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const backing_integer_val = try mod.intern(.{ .opt = .{ .ty = (try mod.optionalType(.type_type)).toIntern(), .val = if (layout == .Packed) val: { - const struct_obj = mod.typeToStruct(struct_ty).?; + const struct_obj = mod.typeToStruct(ty).?; assert(struct_obj.haveLayout()); assert(struct_obj.backing_int_ty.isInt(mod)); break :val struct_obj.backing_int_ty.toIntern(); @@ -17617,7 +17641,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // decls: []const Declaration, decls_val, // is_tuple: bool, - Value.makeBool(struct_ty.isTuple(mod)).toIntern(), + Value.makeBool(ty.isTuple(mod)).toIntern(), }; return Air.internedToRef((try mod.intern(.{ .un = .{ .ty = type_info_ty.toIntern(), @@ -17644,8 +17668,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :t type_opaque_ty_decl.val.toType(); }; - const opaque_ty = try sema.resolveTypeFields(ty); - const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod)); + try sema.resolveTypeFields(ty); + const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod)); const field_values = .{ // decls: []const Declaration, @@ -18511,8 +18535,8 @@ fn retWithErrTracing( else => true, }; const gpa = sema.gpa; - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); const return_err_fn = try sema.getBuiltin("returnError"); @@ -18874,14 +18898,14 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE fn structInitEmpty( sema: *Sema, block: *Block, - obj_ty: Type, + struct_ty: Type, dest_src: LazySrcLoc, init_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; // This logic must be synchronized with that in `zirStructInit`. - const struct_ty = try sema.resolveTypeFields(obj_ty); + try sema.resolveTypeFields(struct_ty); // The init values to use for the struct instance. const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod)); @@ -19674,8 +19698,7 @@ fn fieldType( const mod = sema.mod; var cur_ty = aggregate_ty; while (true) { - const resolved_ty = try sema.resolveTypeFields(cur_ty); - cur_ty = resolved_ty; + try sema.resolveTypeFields(cur_ty); switch (cur_ty.zigTypeTag(mod)) { .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) { .anon_struct_type => |anon_struct| { @@ -19709,7 +19732,7 @@ fn fieldType( else => {}, } return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ - resolved_ty.fmt(sema.mod), + cur_ty.fmt(sema.mod), }); } } @@ -19721,8 +19744,8 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern()); @@ -20048,14 +20071,10 @@ fn zirReify( (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?, ); - const unresolved_elem_ty = child_val.toType(); - const elem_ty = if (abi_align == .none) - unresolved_elem_ty - else t: { - const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); + const elem_ty = child_val.toType(); + if (abi_align != .none) { try sema.resolveTypeLayout(elem_ty); - break :t elem_ty; - }; + } const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val); @@ -25070,8 +25089,8 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { } if (mod.null_stack_trace == .none) { - const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); - const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); + const stack_trace_ty = try sema.getBuiltinType("StackTrace"); + try sema.resolveTypeFields(stack_trace_ty); const target = mod.getTarget(); const ptr_stack_trace_ty = try mod.ptrType(.{ .child = stack_trace_ty.toIntern(), @@ -25523,14 +25542,14 @@ fn fieldVal( return inst; } } - const union_ty = try sema.resolveTypeFields(child_type); - if (union_ty.unionTagType(mod)) |enum_ty| { + try sema.resolveTypeFields(child_type); + if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { const field_index = @as(u32, @intCast(field_index_usize)); return Air.internedToRef((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern()); } } - return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); + return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }, .Enum => { if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { @@ -25749,8 +25768,8 @@ fn fieldPtr( return inst; } } - const union_ty = try sema.resolveTypeFields(child_type); - if (union_ty.unionTagType(mod)) |enum_ty| { + try sema.resolveTypeFields(child_type); + if (child_type.unionTagType(mod)) |enum_ty| { if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { const field_index_u32 = @as(u32, @intCast(field_index)); var anon_decl = try block.startAnonDecl(); @@ -25854,35 +25873,35 @@ fn fieldCallBind( find_field: { switch (concrete_ty.zigTypeTag(mod)) { .Struct => { - const struct_ty = try sema.resolveTypeFields(concrete_ty); - if (mod.typeToStruct(struct_ty)) |struct_obj| { + try sema.resolveTypeFields(concrete_ty); + if (mod.typeToStruct(concrete_ty)) |struct_obj| { const field_index_usize = struct_obj.fields.getIndex(field_name) orelse break :find_field; const field_index = @as(u32, @intCast(field_index_usize)); const field = struct_obj.fields.values()[field_index]; return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); - } else if (struct_ty.isTuple(mod)) { + } else if (concrete_ty.isTuple(mod)) { if (ip.stringEqlSlice(field_name, "len")) { - return .{ .direct = try mod.intRef(Type.usize, struct_ty.structFieldCount(mod)) }; + return .{ .direct = try mod.intRef(Type.usize, concrete_ty.structFieldCount(mod)) }; } if (field_name.toUnsigned(ip)) |field_index| { - if (field_index >= struct_ty.structFieldCount(mod)) break :find_field; - return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr); + if (field_index >= concrete_ty.structFieldCount(mod)) break :find_field; + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(field_index, mod), field_index, object_ptr); } } else { - const max = struct_ty.structFieldCount(mod); + const max = concrete_ty.structFieldCount(mod); for (0..max) |i_usize| { const i = @as(u32, @intCast(i_usize)); - if (field_name == struct_ty.structFieldName(i, mod)) { - return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr); + if (field_name == concrete_ty.structFieldName(i, mod)) { + return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr); } } } }, .Union => { - const union_ty = try sema.resolveTypeFields(concrete_ty); - const fields = union_ty.unionFields(mod); + try sema.resolveTypeFields(concrete_ty); + const fields = concrete_ty.unionFields(mod); const field_index_usize = fields.getIndex(field_name) orelse break :find_field; const field_index = @as(u32, @intCast(field_index_usize)); const field = fields.values()[field_index]; @@ -26081,13 +26100,13 @@ fn structFieldPtr( struct_ptr: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_struct_ty: Type, + struct_ty: Type, initializing: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); + assert(struct_ty.zigTypeTag(mod) == .Struct); - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); try sema.resolveStructLayout(struct_ty); if (struct_ty.isTuple(mod)) { @@ -26234,12 +26253,12 @@ fn structFieldVal( struct_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_struct_ty: Type, + struct_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); + assert(struct_ty.zigTypeTag(mod) == .Struct); - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { .struct_type => |struct_type| { const struct_obj = mod.structPtrUnwrap(struct_type.index).?; @@ -26361,17 +26380,17 @@ fn unionFieldPtr( union_ptr: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_union_ty: Type, + union_ty: Type, initializing: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - assert(unresolved_union_ty.zigTypeTag(mod) == .Union); + assert(union_ty.zigTypeTag(mod) == .Union); const union_ptr_ty = sema.typeOf(union_ptr); const union_ptr_info = union_ptr_ty.ptrInfo(mod); - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field = union_obj.fields.values()[field_index]; @@ -26467,13 +26486,13 @@ fn unionFieldVal( union_byval: Air.Inst.Ref, field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, - unresolved_union_ty: Type, + union_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - assert(unresolved_union_ty.zigTypeTag(mod) == .Union); + assert(union_ty.zigTypeTag(mod) == .Union); - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); const field = union_obj.fields.values()[field_index]; @@ -26733,7 +26752,7 @@ fn tupleFieldPtr( const mod = sema.mod; const tuple_ptr_ty = sema.typeOf(tuple_ptr); const tuple_ty = tuple_ptr_ty.childType(mod); - _ = try sema.resolveTypeFields(tuple_ty); + try sema.resolveTypeFields(tuple_ty); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -26790,7 +26809,8 @@ fn tupleField( field_index: u32, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); + const tuple_ty = sema.typeOf(tuple); + try sema.resolveTypeFields(tuple_ty); const field_count = tuple_ty.structFieldCount(mod); if (field_count == 0) { @@ -26872,6 +26892,7 @@ fn elemValArray( const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; try sema.requireRuntimeBlock(block, src, runtime_src); + try sema.queueFullTypeResolution(array_ty); if (oob_safety and block.wantSafety()) { // Runtime check is only needed if unable to comptime check if (maybe_index_val == null) { @@ -27113,16 +27134,17 @@ const CoerceOpts = struct { fn coerceExtra( sema: *Sema, block: *Block, - dest_ty_unresolved: Type, + dest_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, opts: CoerceOpts, ) CoersionError!Air.Inst.Ref { - if (dest_ty_unresolved.isGenericPoison()) return inst; + if (dest_ty.isGenericPoison()) return inst; const mod = sema.mod; const dest_ty_src = inst_src; // TODO better source location - const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); - const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); + try sema.resolveTypeFields(dest_ty); + const inst_ty = sema.typeOf(inst); + try sema.resolveTypeFields(inst_ty); const target = mod.getTarget(); // If the types are the same, we can return the operand. if (dest_ty.eql(inst_ty, mod)) @@ -29830,16 +29852,15 @@ fn beginComptimePtrLoad( fn bitCast( sema: *Sema, block: *Block, - dest_ty_unresolved: Type, + dest_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, operand_src: ?LazySrcLoc, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); try sema.resolveTypeLayout(dest_ty); - const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); + const old_ty = sema.typeOf(inst); try sema.resolveTypeLayout(old_ty); const dest_bits = dest_ty.bitSize(mod); @@ -30042,8 +30063,8 @@ fn coerceEnumToUnion( const union_obj = mod.typeToUnion(union_ty).?; const field = union_obj.fields.values()[field_index]; - const field_ty = try sema.resolveTypeFields(field.ty); - if (field_ty.zigTypeTag(mod) == .NoReturn) { + try sema.resolveTypeFields(field.ty); + if (field.ty.zigTypeTag(mod) == .NoReturn) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); @@ -30057,12 +30078,12 @@ fn coerceEnumToUnion( }; return sema.failWithOwnedErrorMsg(msg); } - const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { + const opv = (try sema.typeHasOnePossibleValue(field.ty)) orelse { const msg = msg: { const field_name = union_obj.fields.keys()[field_index]; const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), - field_ty.fmt(sema.mod), field_name.fmt(ip), + field.ty.fmt(sema.mod), field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -30426,13 +30447,13 @@ fn coerceTupleToArrayPtrs( fn coerceTupleToStruct( sema: *Sema, block: *Block, - dest_ty: Type, + struct_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, ) !Air.Inst.Ref { const mod = sema.mod; const ip = &mod.intern_pool; - const struct_ty = try sema.resolveTypeFields(dest_ty); + try sema.resolveTypeFields(struct_ty); if (struct_ty.isTupleOrAnonStruct(mod)) { return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); @@ -33728,6 +33749,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; + switch (mod.intern_pool.indexToKey(ty.toIntern())) { + .simple_type => |simple_type| return sema.resolveSimpleType(simple_type), + else => {}, + } switch (ty.zigTypeTag(mod)) { .Struct => return sema.resolveStructLayout(ty), .Union => return sema.resolveUnionLayout(ty), @@ -33768,8 +33793,8 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - if (mod.typeToStruct(resolved_ty)) |struct_obj| { + try sema.resolveTypeFields(ty); + if (mod.typeToStruct(ty)) |struct_obj| { switch (struct_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { @@ -33805,9 +33830,9 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { } struct_obj.status = .have_layout; - _ = try sema.resolveTypeRequiresComptime(resolved_ty); + _ = try sema.resolveTypeRequiresComptime(ty); - if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { + if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { const msg = try Module.ErrorMsg.create( sema.gpa, struct_obj.srcLoc(mod), @@ -34019,8 +34044,8 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const union_obj = mod.typeToUnion(resolved_ty).?; + try sema.resolveTypeFields(ty); + const union_obj = mod.typeToUnion(ty).?; switch (union_obj.status) { .none, .have_field_types => {}, .field_types_wip, .layout_wip => { @@ -34051,9 +34076,9 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { }; } union_obj.status = .have_layout; - _ = try sema.resolveTypeRequiresComptime(resolved_ty); + _ = try sema.resolveTypeRequiresComptime(ty); - if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { + if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { const msg = try Module.ErrorMsg.create( sema.gpa, union_obj.srcLoc(sema.mod), @@ -34227,8 +34252,7 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; switch (ty.zigTypeTag(mod)) { .Pointer => { - const child_ty = try sema.resolveTypeFields(ty.childType(mod)); - return sema.resolveTypeFully(child_ty); + return sema.resolveTypeFully(ty.childType(mod)); }, .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => return sema.resolveStructFully(ty), @@ -34237,6 +34261,7 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveTypeFully(field_ty.toType()); } }, + .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), else => {}, }, .Union => return sema.resolveUnionFully(ty), @@ -34267,8 +34292,8 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveStructLayout(ty); const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const struct_obj = mod.typeToStruct(resolved_ty).?; + try sema.resolveTypeFields(ty); + const struct_obj = mod.typeToStruct(ty).?; switch (struct_obj.status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, @@ -34297,8 +34322,8 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { try sema.resolveUnionLayout(ty); const mod = sema.mod; - const resolved_ty = try sema.resolveTypeFields(ty); - const union_obj = mod.typeToUnion(resolved_ty).?; + try sema.resolveTypeFields(ty); + const union_obj = mod.typeToUnion(ty).?; switch (union_obj.status) { .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, .fully_resolved_wip, .fully_resolved => return, @@ -34322,7 +34347,7 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { _ = try sema.typeRequiresComptime(ty); } -pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { +pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void { const mod = sema.mod; switch (ty.toIntern()) { @@ -34385,7 +34410,7 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { .anyerror_void_error_union_type, .generic_poison_type, .empty_struct_type, - => return ty, + => {}, .undef => unreachable, .zero => unreachable, @@ -34406,42 +34431,52 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { .empty_struct => unreachable, .generic_poison => unreachable, - .type_info_type => return sema.getBuiltinType("Type"), - .extern_options_type => return sema.getBuiltinType("ExternOptions"), - .export_options_type => return sema.getBuiltinType("ExportOptions"), - .atomic_order_type => return sema.getBuiltinType("AtomicOrder"), - .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"), - .calling_convention_type => return sema.getBuiltinType("CallingConvention"), - .address_space_type => return sema.getBuiltinType("AddressSpace"), - .float_mode_type => return sema.getBuiltinType("FloatMode"), - .reduce_op_type => return sema.getBuiltinType("ReduceOp"), - .call_modifier_type => return sema.getBuiltinType("CallModifier"), - .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"), - - _ => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) { + else => switch (mod.intern_pool.items.items(.tag)[@intFromEnum(ty.toIntern())]) { .type_struct, .type_struct_ns, .type_union_tagged, .type_union_untagged, .type_union_safety, + .simple_type, => switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => |struct_type| { - const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty; + const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return; try sema.resolveTypeFieldsStruct(ty, struct_obj); - return ty; }, .union_type => |union_type| { const union_obj = mod.unionPtr(union_type.index); try sema.resolveTypeFieldsUnion(ty, union_obj); - return ty; }, + .simple_type => |simple_type| try sema.resolveSimpleType(simple_type), else => unreachable, }, - else => return ty, + else => {}, }, } } +/// Fully resolves a simple type. This is usually a nop, but for builtin types with +/// special InternPool indices (such as std.builtin.Type) it will analyze and fully +/// resolve the container type. +fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileError!void { + const builtin_type_name: []const u8 = switch (simple_type) { + .atomic_order => "AtomicOrder", + .atomic_rmw_op => "AtomicRmwOp", + .calling_convention => "CallingConvention", + .address_space => "AddressSpace", + .float_mode => "FloatMode", + .reduce_op => "ReduceOp", + .call_modifier => "CallModifer", + .prefetch_options => "PrefetchOptions", + .export_options => "ExportOptions", + .extern_options => "ExternOptions", + .type_info => "Type", + else => return, + }; + // This will fully resolve the type. + _ = try sema.getBuiltinType(builtin_type_name); +} + fn resolveTypeFieldsStruct( sema: *Sema, ty: Type, @@ -35784,7 +35819,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .struct_type => |struct_type| { - const resolved_ty = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); if (mod.structPtrUnwrap(struct_type.index)) |s| { const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { @@ -35792,14 +35827,14 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { field_val.* = field.default_val; continue; } - if (field.ty.eql(resolved_ty, sema.mod)) { + if (field.ty.eql(ty, sema.mod)) { const msg = try Module.ErrorMsg.create( sema.gpa, s.srcLoc(sema.mod), "struct '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| { @@ -35837,7 +35872,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { }, .union_type => |union_type| { - const resolved_ty = try sema.resolveTypeFields(ty); + try sema.resolveTypeFields(ty); const union_obj = mod.unionPtr(union_type.index); const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse return null; @@ -35847,20 +35882,20 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { return only.toValue(); } const only_field = fields[0]; - if (only_field.ty.eql(resolved_ty, sema.mod)) { + if (only_field.ty.eql(ty, sema.mod)) { const msg = try Module.ErrorMsg.create( sema.gpa, union_obj.srcLoc(sema.mod), "union '{}' depends on itself", .{ty.fmt(sema.mod)}, ); - try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); + try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{}); return sema.failWithOwnedErrorMsg(msg); } const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse return null; const only = try mod.intern(.{ .un = .{ - .ty = resolved_ty.toIntern(), + .ty = ty.toIntern(), .tag = tag_val.toIntern(), .val = val_val.toIntern(), } }); @@ -36430,12 +36465,12 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { fn unionFieldIndex( sema: *Sema, block: *Block, - unresolved_union_ty: Type, + union_ty: Type, field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; - const union_ty = try sema.resolveTypeFields(unresolved_union_ty); + try sema.resolveTypeFields(union_ty); const union_obj = mod.typeToUnion(union_ty).?; const field_index_usize = union_obj.fields.getIndex(field_name) orelse return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); @@ -36445,12 +36480,12 @@ fn unionFieldIndex( fn structFieldIndex( sema: *Sema, block: *Block, - unresolved_struct_ty: Type, + struct_ty: Type, field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; - const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); + try sema.resolveTypeFields(struct_ty); if (struct_ty.isAnonStruct(mod)) { return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); } else { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 1ddf211bda..3db6321119 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3134,17 +3134,6 @@ pub const Object = struct { .null_type, .undefined_type, .enum_literal_type, - .atomic_order_type, - .atomic_rmw_op_type, - .calling_convention_type, - .address_space_type, - .float_mode_type, - .reduce_op_type, - .call_modifier_type, - .prefetch_options_type, - .export_options_type, - .extern_options_type, - .type_info_type, => unreachable, .manyptr_u8_type, .manyptr_const_u8_type, diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 06458ea3cd..bbcfbb7047 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -718,7 +718,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void { } try self.eh_frame_relocs_lookup.ensureTotalCapacity(gpa, record_count); - try self.eh_frame_records_lookup.ensureTotalCapacity(gpa, record_count); + try self.eh_frame_records_lookup.ensureUnusedCapacity(gpa, record_count); it.reset(); @@ -768,11 +768,28 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void { else => unreachable, } }; - log.debug("FDE at offset {x} tracks {s}", .{ offset, zld.getSymbolName(target) }); if (target.getFile() != object_id) { + log.debug("FDE at offset {x} marked DEAD", .{offset}); self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true; } else { - self.eh_frame_records_lookup.putAssumeCapacityNoClobber(target, offset); + // You would think that we are done but turns out that the compilers may use + // whichever symbol alias they want for a target symbol. This in particular + // very problematic when using Zig's @export feature to re-export symbols under + // additional names. For that reason, we need to ensure we record aliases here + // too so that we can tie them with their matching unwind records and vice versa. + const aliases = self.getSymbolAliases(target.sym_index); + var i: u32 = 0; + while (i < aliases.len) : (i += 1) { + const actual_target = SymbolWithLoc{ + .sym_index = i + aliases.start, + .file = target.file, + }; + log.debug("FDE at offset {x} tracks {s}", .{ + offset, + zld.getSymbolName(actual_target), + }); + try self.eh_frame_records_lookup.putNoClobber(gpa, actual_target, offset); + } } } } @@ -803,7 +820,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { const unwind_records = self.getUnwindRecords(); - try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(unwind_records.len))); + try self.unwind_records_lookup.ensureUnusedCapacity(gpa, @as(u32, @intCast(unwind_records.len))); const needs_eh_frame = for (unwind_records) |record| { if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true; @@ -839,11 +856,28 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void { .code = mem.asBytes(&record), .base_offset = @as(i32, @intCast(offset)), }); - log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) }); if (target.getFile() != object_id) { + log.debug("unwind record {d} marked DEAD", .{record_id}); self.unwind_relocs_lookup[record_id].dead = true; } else { - self.unwind_records_lookup.putAssumeCapacityNoClobber(target, @as(u32, @intCast(record_id))); + // You would think that we are done but turns out that the compilers may use + // whichever symbol alias they want for a target symbol. This in particular + // very problematic when using Zig's @export feature to re-export symbols under + // additional names. For that reason, we need to ensure we record aliases here + // too so that we can tie them with their matching unwind records and vice versa. + const aliases = self.getSymbolAliases(target.sym_index); + var i: u32 = 0; + while (i < aliases.len) : (i += 1) { + const actual_target = SymbolWithLoc{ + .sym_index = i + aliases.start, + .file = target.file, + }; + log.debug("unwind record {d} tracks {s}", .{ + record_id, + zld.getSymbolName(actual_target), + }); + try self.unwind_records_lookup.putNoClobber(gpa, actual_target, @intCast(record_id)); + } } } } @@ -991,6 +1025,18 @@ pub fn getSymbolName(self: Object, index: u32) []const u8 { return strtab[start..][0 .. len - 1 :0]; } +fn getSymbolAliases(self: Object, index: u32) Entry { + const addr = self.source_address_lookup[index]; + var start = index; + while (start > 0 and + self.source_address_lookup[start - 1] == addr) : (start -= 1) + {} + const end: u32 = for (self.source_address_lookup[start..], start..) |saddr, i| { + if (saddr != addr) break @as(u32, @intCast(i)); + } else @as(u32, @intCast(self.source_address_lookup.len)); + return .{ .start = start, .len = end - start }; +} + pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 { // Find containing atom const Predicate = struct { @@ -1012,11 +1058,8 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 { if (target_sym_index > 0) { // Hone in on the most senior alias of the target symbol. // See SymbolAtIndex.lessThan for more context. - var start = target_sym_index - 1; - while (start > 0 and - self.source_address_lookup[lookup.start..][start - 1] == addr) : (start -= 1) - {} - return @as(u32, @intCast(lookup.start + start)); + const aliases = self.getSymbolAliases(@intCast(lookup.start + target_sym_index - 1)); + return aliases.start; } } return self.getSectionAliasSymbolIndex(sect_id); diff --git a/src/translate_c.zig b/src/translate_c.zig index 5886947b0e..93c85ab8bd 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -965,6 +965,7 @@ fn buildFlexibleArrayFn( field_decl: *const clang.FieldDecl, ) TypeError!Node { const field_qt = field_decl.getType(); + const field_qt_canon = qualTypeCanon(field_qt); const u8_type = try Tag.type.create(c.arena, "u8"); const self_param_name = "self"; @@ -979,7 +980,7 @@ fn buildFlexibleArrayFn( .is_noalias = false, }; - const array_type = @as(*const clang.ArrayType, @ptrCast(field_qt.getTypePtr())); + const array_type = @as(*const clang.ArrayType, @ptrCast(field_qt_canon)); const element_qt = array_type.getElementType(); const element_type = try transQualType(c, scope, element_qt, field_decl.getLocation()); @@ -1049,21 +1050,33 @@ fn buildFlexibleArrayFn( return Node.initPayload(&payload.base); } +/// Return true if `field_decl` is the flexible array field for its parent record fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool { - return qualTypeCanon(field_decl.getType()).isIncompleteOrZeroLengthArrayType(c.clang_context); + const record_decl = field_decl.getParent() orelse return false; + const record_flexible_field = flexibleArrayField(c, record_decl) orelse return false; + return field_decl == record_flexible_field; } +/// Find the flexible array field for a record if any. A flexible array field is an +/// incomplete or zero-length array that occurs as the last field of a record. /// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining /// this because it returns false for a record that ends with a zero-length /// array, but we consider those to be flexible arrays -fn hasFlexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) bool { +fn flexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) ?*const clang.FieldDecl { var it = record_def.field_begin(); const end_it = record_def.field_end(); + var flexible_field: ?*const clang.FieldDecl = null; while (it.neq(end_it)) : (it = it.next()) { const field_decl = it.deref(); - if (isFlexibleArrayFieldDecl(c, field_decl)) return true; + const ty = qualTypeCanon(field_decl.getType()); + const incomplete_or_zero_size = ty.isIncompleteOrZeroLengthArrayType(c.clang_context); + if (incomplete_or_zero_size) { + flexible_field = field_decl; + } else { + flexible_field = null; + } } - return false; + return flexible_field; } fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void { @@ -1117,7 +1130,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD var functions = std.ArrayList(Node).init(c.gpa); defer functions.deinit(); - const has_flexible_array = hasFlexibleArrayField(c, record_def); + const flexible_field = flexibleArrayField(c, record_def); var unnamed_field_count: u32 = 0; var it = record_def.field_begin(); const end_it = record_def.field_end(); @@ -1143,7 +1156,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD unnamed_field_count += 1; is_anon = true; } - if (isFlexibleArrayFieldDecl(c, field_decl)) { + if (flexible_field == field_decl) { const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) { error.UnsupportedType => { try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), {}); @@ -1164,7 +1177,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD else => |e| return e, }; - const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0) + const alignment = if (flexible_field != null and field_decl.getFieldIndex() == 0) @as(c_uint, @intCast(record_alignment)) else ClangAlignment.forField(c, field_decl, record_def).zigAlignment(); |
