aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig30
-rw-r--r--src/Autodoc.zig3
-rw-r--r--src/Compilation.zig7
-rw-r--r--src/InternPool.zig30
-rw-r--r--src/Module.zig55
-rw-r--r--src/Sema.zig377
-rw-r--r--src/codegen/llvm.zig11
-rw-r--r--src/link/MachO/Object.zig65
-rw-r--r--src/translate_c.zig29
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();